This commit is contained in:
NuklearRabbit
2026-07-24 20:29:23 +02:00
commit 66060348da
107 changed files with 14771 additions and 0 deletions
+221
View File
@@ -0,0 +1,221 @@
# Architecture
## Process model
```text
+---------------- Electron renderer ----------------+
| Desktop UI |
| No Node.js, filesystem, process or token access |
+-------------------------+---------------------------+
|
frozen preload API
|
+-------------------------v---------------------------+
| Electron main process |
| |
| IPC validation + trusted sender checks |
| ConfigStore -------- schema 5 + protected Gitea/SSH secrets |
| GitService ----------- Git through execFile args |
| GiteaService --------- repositories + Actions API |
| RepositoryService ---- discovery + aggregation |
| RepositoryMonitor ---- local state awareness |
| PreflightService ----- system/deployment readiness |
| DeploymentService ---- dispatch/poll/verify |
| DiagnosticsService --- JSONL/redaction/support ZIP |
+----------------+--------------------+---------------+
| |
local Git Gitea API
| |
working trees repositories/actions
|
trusted runner
|
fixed allowlisted entry point
|
app + independent status JSON
```
## Trust boundaries
### Renderer
The renderer is untrusted input. It can request only methods exposed by
`preload.cjs`. Node integration is disabled, context isolation and sandboxing
are enabled, and IPC requests are accepted only from the packaged file origin.
Renderer crashes and unhandled rejections are reported through a sanitized
one-way diagnostic method.
### Main process
Paths, URLs, file selections, branch names, commit messages, diagnostic export
modes and deployment requests are checked here. The renderer cannot supply a
server command. UI eligibility is advisory; main-process services re-read the
working tree and remote ancestry immediately before privileged actions.
### Gitea
Gitea supplies repository metadata and the Actions control plane. ForgeFlow
handles run-list response variants, retries servers that reject optional query
filters and can fall back to the older tasks listing. Requests log only method,
API path, status and duration—not authorization headers or request bodies.
### Runner and server
The runner consumes only committed trusted workflows. The root-owned server
entry point reads an exact repository/environment target from a root-owned,
non-writable data file. It validates the full SHA again and uses a
per-environment lock. The runner receives no free-form command from ForgeFlow.
## Local state
`forgeflow-config.json` lives below Electron's platform-specific user-data path
and is written atomically. Schema version 3 contains:
- Gitea connection metadata and an OS-encrypted token blob where available;
- workspace roots and explicit repository mappings;
- favorites and application preferences;
- diagnostic retention and level preferences;
- multiple deployment profiles and last server state;
- up to 250 operation records.
Renderer-visible public state never contains the plaintext or encrypted token.
Structured diagnostic JSONL files live in a separate `diagnostics` directory.
They have independent rotation and retention and never block normal app use when
logging itself fails.
## Repository aggregation
1. Fetch accessible Gitea repositories.
2. Scan bounded workspace roots for Git working trees.
3. Normalize HTTPS and SCP-style SSH remotes.
4. Match local `origin` identity to `owner/repository`.
5. Apply explicit mappings where present.
6. Read Git state with bounded concurrency.
7. Attach favorites, deployment profiles and last server state.
8. Derive attention and ready-to-deploy status.
9. Feed linked paths to the repository monitor.
## Repository clone lifecycle
The first configured project root is the default. The renderer submits only the
current Gitea repository identity and either `default` or `custom` location
mode. The main process resolves the repository again, selects a configured root
or a native-dialog result, calculates the repository-named child path and asks
GitService to inspect it.
```text
repository identity
|
current Gitea metadata
|
project root + safe repository folder name
|
missing / empty / matching checkout / conflict
|
clone or reuse -> save mapping -> refresh -> monitor
```
A matching existing checkout is reused. Different repositories and arbitrary
non-empty folders are rejected.
## Git execution
ForgeFlow invokes the installed Git executable through `execFile`; it never
builds shell command strings. File arguments must remain repository-relative
and cannot contain traversal segments.
Core status command:
```bash
git status --porcelain=v2 --branch -z --untracked-files=all
```
Synchronization is intentionally limited to:
```bash
git pull --ff-only
```
Branch switching requires a clean working tree. Stash supports untracked files.
Deployment and rollback verify the full SHA against `origin/<allowed-branch>`
with `merge-base --is-ancestor`.
## Preflight model
### System preflight
Checks Git, author identity, app storage, diagnostic storage, OS credential
protection, configured workspace roots and—when credentials are present—Gitea
connectivity and repository visibility.
### Deployment preflight
Checks repository link, Git working tree, allowed branch, clean state, upstream,
ahead/behind state, exact remote SHA, local and remote workflow presence,
Actions API access, server status endpoint and healthcheck.
Only failed required checks block readiness. The deployment backend repeats
safety-critical Git/SHA validation after the user continues.
## Repository monitor
The current monitor periodically fingerprints Git state. It establishes a
baseline, reports later changes and pauses during mutating operations to avoid
intermediate noise. It is dependency-free rather than a native filesystem
watcher.
## Deployment lifecycle
```text
requested -> queued -> running -> health/version verification -> terminal
```
A deployment operation stores the exact SHA, fixed profile, environment,
workflow and a UUID request ID. Polling then:
1. finds the matching Actions run by SHA, branch, workflow and dispatch time;
2. normalizes run status;
3. retrieves jobs and locally redacted runner output;
4. maps jobs to ForgeFlow stages;
5. reads the independent status endpoint and healthcheck after runner success;
6. verifies live SHA equality;
7. stores success, rolled-back, failed or cancelled.
The request ID is sent to the workflow and server status document, making one
operation correlatable without using a credential as an identifier.
## Diagnostics pipeline
```text
event -> recursive sanitization -> ordered JSONL write
|
support export requested
|
fresh state + preflight + redacted logs
|
strict/standard privacy transformation
|
fail-closed local secret safety audit
|
ZIP + SHA-256 result
```
Raw runner output is deliberately omitted from exported support bundles.
## Status endpoint
The recommended endpoint is a static JSON file served independently from the
application. It reports live, previous and requested SHAs, request ID, health
and last exit code. See `STATUS_ENDPOINT.md`.
## v0.4 services
- `UpdateService` reads `package.json` at an exact Gitea branch SHA, downloads an
authenticated archive and launches the rollback-capable Windows source updater.
- `SshService` provides pinned-host SSH execution with encrypted password or
private-key passphrase storage.
- `UnraidDeploymentService` inspects existing application folders and performs
exact-SHA Git and Docker Compose deployments without deleting untracked
runtime data.
+58
View File
@@ -0,0 +1,58 @@
# Deployment setup guide
This guide connects one Gitea repository to one server environment without giving the desktop arbitrary shell access.
## 1. Add fixed workflows
Copy these examples into the repository:
```text
examples/gitea-actions/deploy.yml -> .gitea/workflows/deploy.yml
examples/gitea-actions/rollback.yml -> .gitea/workflows/rollback.yml
```
Change the runner label to the label registered for the target environment.
## 2. Install the allowlisted server entry point
Copy `examples/server/forgeflow-deploy` to `/usr/local/bin/forgeflow-deploy`, customize its repository/environment allowlist and make it root-owned:
```bash
sudo install -o root -g root -m 0755 forgeflow-deploy /usr/local/bin/forgeflow-deploy
```
Grant the runner account permission to execute only this entry point where elevation is needed. Do not grant unrestricted shell or Docker administration merely for ForgeFlow.
## 3. Expose deployment status
The example script writes an atomic JSON document beneath `/var/lib/forgeflow-status`. Serve the appropriate file at a fixed HTTPS URL, for example with `examples/server/nginx-forgeflow-status.conf`.
See `STATUS_ENDPOINT.md` for the contract.
## 4. Configure the ForgeFlow profile
Open the repository, choose **Deployments** and add an environment with:
- Name: `Production` or `Staging`.
- Environment: the fixed workflow input.
- Branch: usually `main`.
- Workflow file: `deploy.yml`.
- Rollback workflow: `rollback.yml`.
- Status URL: the JSON endpoint.
- Healthcheck URL: the application health endpoint.
- Confirmation: enabled for production.
## 5. Validate the complete path
Test these scenarios before relying on production:
1. Clean commit and push.
2. Successful deployment to the exact SHA.
3. Gitea runner failure.
4. Application healthcheck failure.
5. Server reports the wrong SHA.
6. Second deployment while the lock is held.
7. Rollback to the recorded previous SHA.
8. Token without sufficient permissions.
Keep a manual recovery path documented even after rollback works.
+150
View File
@@ -0,0 +1,150 @@
# Diagnostics, privacy and support bundles
ForgeFlow v0.3.2 records development-oriented diagnostics locally so failures
can be investigated without requesting the user's Gitea token, SSH key or
server password.
## Storage
Diagnostic events are stored beneath the Electron application-data directory in:
```text
diagnostics/forgeflow-YYYY-MM-DD.jsonl
```
The Diagnostics page displays an aliased path such as `<HOME>` rather than the
Windows account name. Files use restrictive permissions where the operating
system supports them.
Defaults:
- enabled;
- minimum level `info`;
- 14-day retention;
- 8 MB maximum per log segment;
- daily filenames with numbered rotation;
- ordered asynchronous writes;
- no application crash when diagnostic storage itself fails.
These values can be changed in **Diagnostics -> Recording policy**.
## What an event can contain
Useful fields include:
- UTC timestamp;
- level and stable event name;
- per-launch session identifier;
- operation or deployment request identifier;
- Git/Gitea operation outcome;
- HTTP status, duration and endpoint path without request headers;
- repository state and branch/SHA metadata;
- preflight result;
- sanitized exception name, code, message and stack;
- renderer crash or unhandled-rejection metadata.
ForgeFlow does not log IPC payloads, request authorization headers or Gitea
response bodies merely because a request was made.
## Redaction
Every event passes through a recursive sanitizer before it is written.
Redaction covers:
- the currently active Gitea token;
- token, password, authorization, credential, API-key, client-secret and
encrypted-token object fields, including camelCase variants;
- bearer/token/basic authorization values in strings;
- common token query parameters;
- credentials embedded in URLs;
- PEM private-key blocks;
- known Gitea/Git hosting token patterns;
- Windows, macOS and Linux home-directory paths;
- application source path aliases;
- circular data structures and oversized strings.
Credential values are replaced with `[REDACTED]`; user paths use aliases such as
`<HOME>`.
## Support bundle
**Create diagnostic ZIP** exports a local archive containing:
```text
manifest.json
safety-audit.json
README.txt
system.json
diagnostics-status.json
configuration-sanitized.json
repositories-sanitized.json
operations-sanitized.json
preflight.json
context.json
logs/*.jsonl
```
The application returns the SHA-256 of the generated archive so a shared file
can be identified exactly.
### Excluded data
The bundle intentionally excludes:
- plaintext Gitea access tokens;
- Electron `safeStorage` encrypted-token blobs;
- request authorization headers;
- passwords and private keys;
- raw Gitea runner logs;
- arbitrary environment-variable dumps;
- full local file contents and Git diffs.
ForgeFlow does not automatically ingest or persist raw runner output. Job names,
statuses and safe operation summaries are stored locally; full runner output remains
available only in the trusted Gitea Actions interface when deeper server-side
investigation is necessary.
## Privacy modes
### Standard
Preserves repository names and user-facing identifiers. Local home paths and
credentials are still redacted. Use when the recipient already knows the
project context.
### Strict
Additionally replaces repository and user identifiers with deterministic
SHA-256-based aliases. Related events remain correlatable without revealing the
original names.
## Fail-closed bundle audit
Immediately before writing the archive, ForgeFlow scans every prepared entry
for:
- the known active runtime secret values;
- private-key begin markers;
- unredacted credentials embedded in HTTP(S) URLs.
The result is stored as `safety-audit.json`. When a finding remains, archive
creation is aborted and the unsafe ZIP is not written.
## Practical limitation
No generic logger can mathematically identify every unknown secret if a third-
party process prints an arbitrary value without a label or recognizable format.
ForgeFlow reduces this risk by not including raw runner logs, not recording IPC
payloads and applying both structured and textual redaction. Always inspect a
support bundle before sharing it, particularly when custom integrations have
been added.
## Development workflow after a failure
1. Reproduce the issue once when safe.
2. Note the approximate time and repository/environment.
3. Run the relevant preflight.
4. Export a Strict diagnostic bundle.
5. Keep the returned SHA-256 with the bug report.
6. Describe the visible action that failed.
7. Share no separate token, key or password.
+147
View File
@@ -0,0 +1,147 @@
# LumaOps server versus Gitea audit
This audit compares the supplied `lumaops_server.zip` and `LumaOps_gitea.zip`.
## Main result
The main Unraid working tree and the supplied Gitea checkout point to exactly the same commit:
```text
d42d4a7f08240c478d07466e3fabec654dc71367
```
Latest subject:
```text
Preserve colors across Aura zone updates
```
There is therefore no source-version drift at the root of the live LumaOps folder.
## Root Git repository
The root `.git` directory should remain in place. It enables:
- exact-SHA verification;
- controlled fetch and reset;
- a reliable previous-version reference;
- rollback without copying a second complete source tree.
The archived server copy showed one root status difference for `scripts/unraid-hardware-setup.sh`: file mode `100755 → 100644`. This is consistent with Unix executable bits being lost during ZIP handling. The file content did not differ. Check the executable bit directly on Unraid before deployment.
## Origin URL mismatch to resolve
The supplied server root uses:
```text
ssh://git@127.0.0.1:222/NuklearRabbit/LumaOps.git
```
The supplied Gitea checkout uses:
```text
https://gitea.itworx.tech/Jens/LumaOps.git
```
Although both archives currently point to the same commit, these are different
repository paths. Before the first ForgeFlow deployment, choose the server-
reachable URL for the authoritative `Jens/LumaOps` repository, for example an
SSH URL through `127.0.0.1:222` when Gitea runs on the same Unraid host.
ForgeFlow 0.4 detects this mismatch. Deployment is blocked unless the profile
matches the existing origin or **Align an existing server origin to this URL**
is explicitly enabled.
## Runtime and persistent paths
The server copy contains runtime data that must not be replaced by source updates:
- `appdata/`
- `data/`
- `logs/`
- `.env` and application-specific configuration
The repository `.gitignore` already excludes the principal runtime paths. ForgeFlow's SSH strategy uses Git reset without `git clean`, so untracked persistent data remains in place.
## Compose and Unraid integration
The root `docker-compose.yml` is already suitable as the authoritative deployment definition. It includes:
- build context at the project root;
- container name `lumaops`;
- the Unraid `dockerman` label;
- a Web UI label;
- an Unraid icon label;
- `${WEB_PORT:-1223}:${APP_PORT:-8080}`;
- persistent relative volumes;
- USB, HID and I²C devices;
- a healthcheck.
ForgeFlow should use this existing Compose file rather than generate a replacement. Ports and complex device mappings belong in the repository's maintained Compose definition.
The supplied `.dockerignore` already excludes `.git`, so keeping the root Git
working tree does **not** copy Git history into the Docker build context. It does
not yet explicitly exclude the existing runtime/legacy folders `appdata/`,
`data/`, `logs/` and `source/`. Before the first production rebuild, add the
paths that are not build inputs:
```text
appdata/
data/
logs/
source/
.forgeflow/
```
ForgeFlow 0.4 detects existing preserved paths and nested Git repositories that
are missing from `.dockerignore` and reports them as a preflight warning. The
tool does not silently edit a source-controlled `.dockerignore`; the correction
should be committed to Gitea so every deployment uses the same build context.
## Nested `source/` repository
The server archive also contains a nested Git working tree under:
```text
source/
```
Its HEAD is:
```text
b746a52af1613f4291235f5e8165b8197a269a79
```
It was ahead of its own upstream and included rebase metadata in the supplied archive. The root Compose file uses build context `.` and does not reference `source/`. This strongly indicates that `source/` is an abandoned or historical checkout rather than the active deployment source.
ForgeFlow reports this as a nested-repository warning and does not remove it automatically.
Recommended migration:
1. Back up `/mnt/user/appdata/lumaops`.
2. Verify on Unraid that `docker compose config` uses the root project.
3. Stop changing files in `source/`.
4. Rename it temporarily to `source.legacy-backup`.
5. Rebuild and test LumaOps from the root.
6. Remove the legacy copy only after a successful validation period.
Do not delete the root `.git` directory. Also do not delete the nested `source/`
directory as part of the first ForgeFlow test. Treat its cleanup as a separate,
backed-up migration after the root deployment and rollback have both been
validated.
## Recommended ForgeFlow profile
```text
Provider: SSH / Unraid
Server folder: lumaops
Branch: main
Compose mode: Repository/server Compose
Compose file: docker-compose.yml
Clone URL: the Git URL reachable from Unraid
Healthcheck: the existing LumaOps health URL, when exposed
Preserve paths: .env, appdata, data, logs, config, compose.override.yml
```
No folder rename is required for LumaOps because `lumaops` already aligns with the repository name.
+32
View File
@@ -0,0 +1,32 @@
# ForgeFlow 0.2.0 release notes
ForgeFlow 0.2.0 turns the original visual prototype into a substantially more operational personal release cockpit.
## Highlights
- Automatic repository status monitoring with safe pause/resume around Git mutations.
- Commit-only and commit-and-push flows with recoverable push failures.
- Branch creation, switching, publication and stash workflows.
- Favorite repositories and action-oriented attention queues.
- Multiple deployment environments per repository.
- Exact remote-branch SHA verification before deploy and rollback.
- Gitea Actions run, job and available log polling.
- Live server version, previous version and health verification.
- Fixed-workflow rollback to a recorded full commit SHA.
- Stronger IPC, URL, path and secret-handling controls.
- Reworked renderer with command palette and live deployment states.
- 21 passing automated tests, including real temporary Git remotes.
- Headless browser smoke coverage at three desktop viewport sizes.
## Upgrade notes
Configuration is migrated automatically to schema version 2. Existing Gitea tokens are preserved when the settings form is saved with an empty token field.
Deployment profiles now support independent branch, workflow, rollback workflow, healthcheck and status endpoint settings. Review existing profiles before using them against production.
## Known limitations
- No signed installer or automatic update channel is included in this source release.
- Partial-hunk staging, conflict resolution and protected-branch awareness are not yet implemented.
- Gitea Actions behavior still needs acceptance testing against the intended Gitea and act_runner versions.
- Native desktop notifications, tray mode and accessibility acceptance remain future work.
+140
View File
@@ -0,0 +1,140 @@
# ForgeFlow 0.3.0 release notes
Release date: 2026-07-24
Release type: self-service test release
## Goal
Version 0.3.0 closes the gap between a functional developer preview and a build
that can be configured and tested by its owner without sharing credentials with
a developer. The release concentrates on setup guidance, deterministic
preflight checks, safe diagnostics and server-side allowlisting.
## Setup and readiness
- Replaced the lightweight onboarding with a five-step setup wizard.
- Added a computer readiness preflight for Git, Git identity, writable app data,
writable diagnostics and OS credential encryption.
- Added a Gitea validation stage before setup completion.
- Added visible repository discovery results.
- Added safe setup diagnostics before Gitea is connected.
- Added a comprehensive start page and end-to-end setup guide.
- Added a JSON-capable command-line doctor for local environment validation.
## Deployment preflight
A deployment now receives a visible preflight before confirmation and a second
mandatory backend validation immediately before dispatch. Checks include:
- linked local Git repository;
- allowed deployment branch;
- clean working tree;
- configured upstream;
- local/remote ahead and behind state;
- exact full SHA on the remote branch;
- local deploy and rollback workflow files;
- remote workflow visibility through Gitea;
- Gitea Actions API availability;
- deployment status endpoint;
- application health endpoint.
Optional environment checks can warn without hiding required failures.
Deployment cannot bypass the mandatory checks through the renderer.
## Diagnostic logging
- Added ordered structured JSONL logging in the Electron app-data directory.
- Added daily files, size rotation and retention pruning.
- Added configurable logging level, retention and file-size policy.
- Added process, renderer, Git, repository, Gitea, IPC, preflight and deployment
diagnostics.
- Added per-launch session IDs and per-operation deployment request IDs.
- Added a no-throw logging design so diagnostic storage does not crash the app.
- Added local clear and open-folder controls.
## Secret and privacy protection
- Added recursive sensitive-key detection, including camelCase variants.
- Added bearer/basic/token/password/API-key/client-secret redaction.
- Added runtime-secret replacement.
- Added URL credential, token query parameter and private-key redaction.
- Added common hosting-token pattern redaction.
- Added user-home and source-root path aliases.
- Added strict privacy mode with deterministic identifier hashing.
- Stopped automatically ingesting or persisting raw runner logs; full output stays in Gitea.
- Added fail-closed bundle auditing before the ZIP is written.
- Added SHA-256 output for every generated support bundle.
No Gitea token, SSH key or server password is needed by the developer to use
these diagnostics.
## Support bundle contents
A support bundle can contain:
- manifest and safety audit;
- system and application version information;
- sanitized public configuration;
- sanitized repository state;
- sanitized operation history;
- latest preflight report;
- safe diagnostic status;
- redacted JSONL logs.
It intentionally excludes protected token blobs, authorization headers,
private keys, source files, Git diffs, environment dumps and raw runner output.
## Server deployment hardening
- Moved target definitions to a root-owned `/etc/forgeflow/targets.conf` file.
- Added exact repository/environment allowlisting.
- Made the server status URL mandatory and require matching SHA plus request ID before success.
- Added configuration ownership and permission checks.
- Added absolute and restricted path validation.
- Added exact remote-SHA and branch ancestry validation.
- Added per-target `flock` locking.
- Added Docker Compose result and health verification.
- Added current, previous, requested SHA, request ID and exit code to server
status output.
- Added a restrictive sudoers template for the runner.
- Added explicit deploy and rollback workflow request-ID inputs.
- Added backend repository re-resolution so renderer-supplied paths and identities
cannot select an arbitrary local folder or Gitea repository.
- Captured pre-dispatch Actions run IDs so polling cannot attach to an older run
with the same commit SHA.
- Required repository, environment, live SHA, requested SHA, request ID, zero
server exit code and explicit health success before marking a release complete.
- Restricted rollback to the exact previous SHA currently reported by the server
status endpoint.
## User interface
- Added a dedicated Diagnostics workspace.
- Added system and deployment preflight presentation.
- Added diagnostic policy controls.
- Added Standard and Strict support-bundle export.
- Added support-bundle checksum and reveal action.
- Added readiness explanations to onboarding.
- Replaced duplicate sidebar navigation with a compact safe-diagnostics state.
## Validation
- 39 required project files validated.
- 35 JavaScript files passed syntax checks.
- 36 of 36 automated tests passed.
- Two real temporary Git remotes remain part of the integration suite.
- New tests cover redaction, diagnostic rotation/export, support ZIP generation,
fail-closed safety auditing, preflight and Gitea workflow-file checks.
## Known boundaries
- The release is not code-signed.
- A platform-native installer is not guaranteed by the source ZIP alone.
- The private Gitea, runner and server environment still requires the documented
local acceptance test.
- Application-specific compose commands and health endpoints remain target
configuration, because they cannot be inferred safely.
- No redactor can mathematically identify an arbitrary unknown secret printed by
custom third-party code; raw runner logs therefore remain only in the trusted
Gitea Actions interface, and exported bundles should still be inspected before
sharing.
+25
View File
@@ -0,0 +1,25 @@
# ForgeFlow 0.3.1 release notes
## Windows environment-doctor hotfix
Version 0.3.1 fixes a Windows-only false negative in the environment doctor.
The setup script could invoke npm successfully, install all dependencies and then
report `spawn npm ENOENT` from Node.js. Windows exposes npm through a command
shim (`npm.cmd`), which cannot always be executed directly through
`child_process.execFile`.
The doctor now:
- uses `npm_execpath` through the active Node executable when launched by npm;
- falls back to `cmd.exe /c npm --version` on Windows;
- continues to invoke npm directly on Linux and macOS;
- reports which safe invocation path succeeded;
- reads its displayed application version from `package.json` instead of a
duplicated hard-coded value.
Three regression tests cover npm-script execution, the Windows command-shim
fallback and the normal non-Windows path.
The npm deprecation messages printed during dependency installation are warnings
from transitive build-tool dependencies. They were not the cause of the setup
failure and do not prevent ForgeFlow from starting.
+72
View File
@@ -0,0 +1,72 @@
# ForgeFlow 0.3.2 release notes
## Automatic clone destinations
The normal **Clone from Gitea** action no longer opens a Windows folder picker
for every repository. ForgeFlow now:
1. uses the first configured project root as the default;
2. derives a safe folder name from the repository clone URL;
3. creates `<project-root>/<repository-name>`;
4. clones into that folder;
5. validates the resulting Git repository;
6. saves the repository mapping;
7. starts monitoring the working tree;
8. opens the linked repository in ForgeFlow.
Example:
```text
Default project root: C:\Users\Jens\Projects
Gitea repository: Jens/Portfolio
Automatic target: C:\Users\Jens\Projects\Portfolio
```
A separate **Choose another location** action remains available for exceptional
cases. That choice selects a parent project root; ForgeFlow still creates the
repository-named subfolder itself.
## Existing-folder safety
The clone backend now inspects the automatic target before running Git:
- a missing target is created through `git clone`;
- an existing empty directory is accepted;
- an existing Git checkout with the same normalized origin is linked;
- a different Git repository is blocked;
- an ordinary non-empty directory is blocked;
- a file at the target path is blocked.
ForgeFlow never silently overwrites a conflicting folder and does not create a
duplicated `Repository\Repository` directory.
## Security and consistency
The renderer no longer supplies a free-form remote URL or clone destination to
the privileged Git operation. It sends the Gitea repository identity and a
location mode. The main process then:
- resolves the current repository again from Gitea;
- selects the configured root or a native-dialog result;
- calculates the destination itself;
- performs conflict checks;
- clones or reuses the checkout;
- persists the mapping atomically.
Clone diagnostics contain repository identity, target, branch and commit state,
but no Gitea token or authorization header.
## Validation
Version 0.3.2 contains 45 passing automated tests. New coverage includes:
- HTTPS and SSH repository folder-name derivation;
- automatic target construction;
- missing and empty target handling;
- same-origin checkout reuse;
- different-repository rejection;
- non-empty ordinary-folder rejection;
- file-at-target rejection.
Existing Git, deployment, diagnostics, redaction, rollback and Windows doctor
tests continue to pass.
+57
View File
@@ -0,0 +1,57 @@
# ForgeFlow 0.4.0 release notes
## Scrollable change list
The changed-file panel now has an independent bounded vertical scroll area. Large commits no longer make lower files unreachable.
## Commit readiness
The action panel now labels the commit message as required and displays the exact reason why commit actions are disabled. Selected files are staged automatically during commit; manual staging remains available as an optional index-review step.
## ITWorx.tech branding
The supplied ITWorx.tech logo is integrated into the title bar, first-run setup and application icons.
## Built-in source updater
ForgeFlow can check the configured private Gitea repository, defaulting to `Jens/ForgeFlow` on `main`.
The updater:
- reads the remote `package.json` at an exact branch commit;
- compares semantic versions;
- downloads an authenticated exact-SHA archive;
- verifies a SHA-256 checksum;
- closes ForgeFlow;
- backs up the current source;
- installs dependencies;
- runs the complete quality gate;
- restores the previous source when validation fails;
- restarts ForgeFlow.
## SSH / Unraid deployment
A server can be configured once with hostname, SSH port, username, encrypted credentials and `/mnt/user/appdata` as base path.
Deployment profiles support:
- existing Git-backed application folders;
- automatic new folder creation;
- exact commit verification;
- pinned SSH host identity;
- existing or generated Compose configuration;
- host and container ports;
- Unraid Web UI and icon labels;
- server-folder mapping;
- tracked-change blocking;
- nested-Git warnings;
- runtime-data preservation;
- rollback to the previous SHA.
## LumaOps audit
The supplied server and Gitea roots both match commit `d42d4a7f08240c478d07466e3fabec654dc71367`. The root Git checkout and Compose file should remain. A stale nested `source/` Git checkout is documented for controlled cleanup.
## Validation
ForgeFlow 0.4.0 has 59 passing automated tests, including real temporary Git remotes, update exact-SHA checks, SSH path safety, renderer workflow contracts, diagnostics redaction, exact previous-SHA rollback enforcement and deployment controls.
+26
View File
@@ -0,0 +1,26 @@
# ForgeFlow 0.4.1 release notes
## Windows Bash path fix
ForgeFlow 0.4.1 fixes the source quality gate on Windows when the project is stored at a path such as `C:\Projects\ForgeFlow`.
The previous verifier passed an absolute Windows path directly to `bash -n`. Bash interpreted the backslashes as escape characters, producing a collapsed path such as `C:ProjectsForgeFlow...` and a false validation failure.
The verifier now starts Bash with the ForgeFlow project root as its working directory and passes the deployment example as a relative POSIX path:
```text
examples/server/forgeflow-deploy
```
This keeps the project root separate from the script argument and works across Windows Git Bash, Linux and macOS.
## Regression coverage
New automated coverage verifies that:
- a Windows project root remains in `cwd`;
- no drive letter or backslash is passed as the Bash script argument;
- absolute and escaping script paths are rejected;
- Bash validation succeeds from a project root containing spaces.
No Gitea token, repository mapping, SSH credential, deployment profile or diagnostic history is changed by this update.
+29
View File
@@ -0,0 +1,29 @@
# ForgeFlow 0.4.2
## Windows Git Bash reliability hotfix
This release fixes the two remaining Windows-only failures, including the temporary-directory lock seen during cleanup while validating the 0.4.1 recovery update.
### Remote shell transport
SSH / Unraid scripts are now sent through a single-line base64 transport and decoded by Bash on the server. This removes nested quote parsing from the transport layer and prevents Git Bash from misreading multiline commands, single quotes, or newline-stripping expressions.
The generated command contains no raw multiline payload. The decoded script still enables strict shell mode, disables interactive Git prompts, and requires batch-mode SSH for server-side Git operations.
### Temporary-directory lock cleanup
The Bash syntax regression test now retries cleanup when Windows briefly retains a working-directory handle after `bash -n` exits. A successful syntax validation is no longer reported as failed solely because of a short-lived `EBUSY`, `EPERM`, or `ENOTEMPTY` cleanup condition.
### Additional correction
The remote status reader now invokes `base64` with the status filename in the correct argument position before stripping CR/LF characters.
## Regression coverage
Coverage verifies:
- Windows Git Bash execution from a project root containing spaces;
- a single-line base64 transport for generated Unraid inspection commands;
- preserved runtime-path inspection without nested quoting failures;
- strict, non-interactive server-side Git settings after decoding;
- safe rollback to ForgeFlow 0.4.0 when an update validation fails.
+9
View File
@@ -0,0 +1,9 @@
# ForgeFlow 0.4.3
## Full clean release
- Replaced the OS-dependent local Bash/Windows-temp-path Unraid inspection test with a platform-independent mocked SSH inspection contract.
- The SSH inspection command is still verified to use Base64 transport and the returned Unraid metadata is parsed and evaluated deterministically.
- Removed the false Windows failure where a local temporary path was interpreted as a remote Linux path.
- Regression coverage confirms preserved runtime paths, nested Git directories, `.dockerignore` handling, and remote target resolution.
- This release is distributed as a complete source package rather than another incremental updater.
+95
View File
@@ -0,0 +1,95 @@
# ForgeFlow roadmap
## Delivered through v0.4
- coherent Local -> Gitea -> Server desktop model;
- protected Gitea credential storage and strict IPC boundary;
- real Git status, diff, stage, commit, push, fetch and fast-forward pull;
- branches, stashes, favorites and automatic local awareness;
- multiple Gitea Actions and SSH / Unraid deployment profiles;
- exact-SHA remote-branch validation, runner polling, request-ID verification, health and rollback;
- five-step readiness/setup wizard;
- system and deployment preflight engine;
- structured rotating diagnostic JSONL logs;
- aggressive credential/path redaction;
- standard/strict support bundles with SHA-256 and fail-closed safety audit;
- no automatic ingestion or persistence of raw runner logs;
- root-owned declarative server target configuration;
- cross-layer request-ID correlation;
- canonical end-to-end setup guide;
- 36 automated tests.
The source is now intended to be locally configured and testable without
sharing credentials. It remains a developer preview until a real environment
acceptance pass is completed.
## Milestone A — Real personal acceptance
- run the canonical setup guide on the target Windows machine;
- connect the actual Gitea instance locally;
- use one non-critical staging repository;
- register a narrowly scoped trusted runner;
- install the target configuration, entry point and status endpoint;
- pass Deployment preflight;
- validate commit -> push -> deploy -> status -> health -> rollback;
- deliberately test stopped runner, wrong branch, missing workflow, failed
health and lock contention;
- export/inspect a strict diagnostic bundle from a failed test;
- capture only non-secret environment-specific adjustments in documentation.
Exit: one real application can be released and restored without code changes to
ForgeFlow itself.
## Milestone B — Git completeness
- partial-hunk staging/discard;
- amend and signing checks;
- richer branch publication/upstream controls;
- conflict helper and editor integration;
- protected-branch awareness;
- pull-request creation;
- submodule/worktree policy.
## Milestone C — Desktop operations
- native notifications and system tray;
- background start preference;
- notification center;
- native menus and expanded keyboard navigation;
- configurable editor/terminal commands;
- repository attention rules and snoozing;
- safer periodic remote fetch scheduling.
## Milestone D — Recovery and audit
- append-only audit export distinct from diagnostics;
- deployment notes and release annotations;
- explicit reconciliation of externally deployed versions;
- per-environment recovery runbook links;
- encrypted configuration backup/restore without token export;
- deployment freeze and maintenance-window policies.
## Milestone E — Additional controlled adapters
- mutually authenticated ForgeFlow server agent;
- Portainer stack deployment;
- systemd adapter;
- Kubernetes adapter.
Every adapter must retain exact version identity, allowlisting, lock control,
health verification, diagnostic correlation and no arbitrary shell input.
## Milestone F — Productization
- Windows installer/portable acceptance;
- macOS/Linux package validation;
- code signing, notarization and signed updates;
- dependency/secret/package scans;
- accessibility review;
- hundreds-of-repositories performance tests;
- opt-in privacy-aware crash reporting;
- documented Gitea/Git/runner support matrix;
- stable configuration migration rollback policy.
- built-in private-Gitea source updater with backup and rollback;
- Unraid server inventory, generated basic Compose and exact-SHA SSH deployment.
+132
View File
@@ -0,0 +1,132 @@
# Security model
ForgeFlow bridges developer credentials, local source trees and production
release controls. The design favors constrained operations over arbitrary
flexibility.
## Desktop boundary
- `nodeIntegration: false`;
- `contextIsolation: true`;
- renderer sandbox enabled;
- Content Security Policy limited to packaged resources;
- narrow frozen preload API;
- IPC rejected unless it originates from the packaged file renderer;
- external navigation restricted to HTTP(S);
- renderer errors reported through sanitized diagnostic IPC;
- support-bundle reveal restricted to the last archive created by the main
process.
## Credentials and persistence
- Gitea token encrypted through Electron `safeStorage` where available;
- session-only fallback when OS encryption is unavailable;
- token omitted from renderer-visible public state;
- encrypted token blob excluded from diagnostic bundles;
- blank settings token field preserves the existing token;
- atomic config replacement and restrictive permissions where supported;
- service URLs reject embedded user credentials;
- no token is required by setup/build scripts or documentation.
## Git operations
- Git executed through `execFile` argument arrays, never shell interpolation;
- local repository and Git root verified;
- file actions accept only repository-relative paths;
- absolute paths, traversal and NUL characters rejected;
- clone remotes restricted to supported Git protocols; embedded passwords
rejected;
- renderer supplies repository identity rather than a free-form remote URL;
- automatic clone targets are calculated in the main process below a selected
project root;
- matching existing origins may be linked, while different repositories and
non-empty ordinary folders are blocked;
- branch names validated by Git;
- fast-forward-only pull;
- branch switching/creation require a clean tree;
- selected-commit flow refuses hidden staged files outside the selection;
- monitor pauses around mutating actions.
## Deployment
- fixed workflow filenames, branch and environment;
- full 4064 character SHA required;
- local state re-read immediately before dispatch;
- clean, published and synchronized branch required;
- deployment SHA must equal local `HEAD`;
- deploy and rollback SHA must belong to the allowed remote branch;
- no free-form server commands over IPC or workflow inputs;
- mandatory deployment preflight in the normal UI flow;
- backend validation repeated after preflight;
- exact target displayed in confirmation;
- independent health and live-SHA checks;
- rollback uses a separate fixed workflow and previous full SHA;
- UUID request ID correlates desktop, workflow and server state.
## Diagnostics and redaction
- structured events are sanitized before writing;
- IPC payloads and HTTP authorization headers are not logged;
- sensitive object keys, including camelCase, are removed;
- known active tokens, authorization strings, query tokens, URL passwords,
private-key blocks and common token formats are redacted;
- home/source paths are aliased;
- strings and collections are bounded;
- logs rotate by day/size and expire by retention policy;
- support bundles offer deterministic strict-privacy aliases;
- raw runner logs, diffs and source file contents are omitted from bundles;
- bundle creation performs a final fail-closed scan for known secrets,
private-key markers and URL credentials;
- bundle SHA-256 is displayed for exact identification.
No generic detector can identify a completely unknown arbitrary secret printed
without context by third-party code. ForgeFlow minimizes that residual risk by
not exporting raw runner output and by requiring user inspection before sharing.
## Runner boundary
Use a production-capable runner only for repositories you trust. Give it a
label unique to the intended environment and the narrowest repository or
organization scope.
Avoid exposing a host Docker socket to untrusted jobs. Treat a runner capable of
host deployment as privileged infrastructure.
## Server entry point
The runner account should not receive unrestricted sudo or SSH access. The
included model uses:
- root-owned `/usr/local/bin/forgeflow-deploy`;
- root-owned `/etc/forgeflow/targets.conf` without group/other write access;
- a sudoers rule for that exact executable only;
- exact repository/environment matching;
- absolute-path and branch validation;
- full-SHA remote ancestry proof;
- per-target `flock` lock;
- fixed Compose and healthcheck configuration;
- atomic non-secret status JSON;
- previous-SHA recording and non-zero failure exits.
## Remaining release hardening
- code-sign packages and signed updates;
- validate private CA/TLS behavior in the target network;
- dependency, secret and binary scans in CI;
- package-level IPC/navigation regression tests;
- OS-specific credential storage and installer acceptance;
- rate/approval policies for team use;
- threat-model every future deployment adapter separately.
## SSH and updater additions
- SSH passwords and private-key passphrases use Electron `safeStorage`;
- diagnostics receive those runtime secrets only for redaction and never export
encrypted credential fields;
- SSH deployment requires a pinned host-key fingerprint;
- remote folders and Compose paths are validated against traversal;
- tracked server-side changes block exact-SHA reset;
- updater tokens are sent only to the configured Gitea origin;
- update archives are checksummed and validated by the full local quality gate;
- source backup is restored when an update fails.
+485
View File
@@ -0,0 +1,485 @@
# ForgeFlow setup and first-test guide
This is the canonical guide for turning the source release into a locally
configured desktop application and testing one complete path:
```text
local change -> commit -> push -> exact-SHA deployment -> healthcheck -> rollback
```
You never need to provide your Gitea token, SSH key or server credentials to a
developer. Enter them only on the computer or server where they belong.
---
## Part 1 — Prepare the Windows desktop
### 1. Extract the release
Extract the complete ForgeFlow ZIP to a normal local directory, for example:
```text
C:\Tools\ForgeFlow
```
Avoid running it directly from inside the ZIP or from a temporary email folder.
### 2. Install the prerequisites
Required:
- Node.js 22 or newer;
- npm, normally installed with Node.js;
- Git for Windows available on `PATH`;
- a normal signed-in Windows desktop session so Electron can use OS credential
encryption.
Optional manual check:
```powershell
node --version
npm --version
git --version
git config --global user.name
git config --global user.email
```
Configure the Git identity when either value is empty:
```powershell
git config --global user.name "YOUR NAME"
git config --global user.email "YOUR EMAIL"
```
### 3. Run the local setup command
Open PowerShell in the extracted folder and run:
```powershell
Set-ExecutionPolicy -Scope Process Bypass
.\setup-windows.ps1
```
This command:
1. checks Node.js, npm and Git;
2. installs the declared project dependency versions;
3. runs source validation and all automated tests;
4. starts the Electron desktop application.
No Gitea or server credential is requested by the PowerShell script.
---
## Part 2 — Complete the ForgeFlow desktop wizard
The first launch uses five explicit steps.
### Step 1. Readiness
Select **Run readiness check**. ForgeFlow verifies:
- Git CLI availability;
- Git author identity;
- writable application storage;
- writable diagnostic storage;
- availability of operating-system credential encryption.
Warnings are informative. Red required checks block completion until resolved.
A safe setup diagnostic ZIP can already be exported at this stage.
### Step 2. Gitea
Create a Gitea access token (personal access token) in your own Gitea account. The exact scope labels
can vary by Gitea version. Give it only the minimum rights needed for:
- reading the repositories you want to show in ForgeFlow;
- reading repository contents and branches;
- reading Actions runs and jobs;
- dispatching the fixed deployment and rollback workflows.
Do not put this token in a Markdown file, `.env`, workflow or chat message.
Enter locally in ForgeFlow:
```text
Instance URL: https://YOUR-GITEA-HOST
Access token: PASTE LOCALLY IN THE PASSWORD FIELD
```
Select **Validate & continue**. ForgeFlow confirms the user identity and
repository access. When OS encryption is available, the token is stored with
Electron `safeStorage`; otherwise it remains session-only and must be entered
again after restarting.
### Step 3. Folders
Choose one or more project roots that contain local repositories, for
example:
```text
C:\Development
D:\Projects
```
Do not select the entire system disk. A focused project root produces faster
and clearer discovery.
The first configured root is also the default clone destination. When cloning
`owner/repository`, ForgeFlow automatically creates:
```text
<first-project-root>\repository
```
The normal **Clone from Gitea** action does not open a folder picker. Use
**Choose another location** only when a repository belongs under a different
parent directory. ForgeFlow still creates the repository-named subfolder.
### Step 4. Discovery
ForgeFlow scans Git metadata and matches each local `origin` to a Gitea
repository. Generated dependency directories are skipped.
### Step 5. Ready
Enter ForgeFlow. Repositories that could not be matched can still be linked or
cloned from their repository screen. A clone is automatically linked and
monitored after Git completes.
---
## Part 3 — Prepare one repository for deployment
Start with a non-critical staging application when possible.
### 1. Verify the local repository
The repository should have:
- a configured `origin` pointing to the same Gitea repository;
- a normal branch such as `main`;
- no unresolved conflicts;
- an upstream branch after the first push.
### 2. Add the fixed Gitea Actions workflows
Copy:
```text
examples/gitea-actions/deploy.yml
examples/gitea-actions/rollback.yml
```
to the target repository as:
```text
.gitea/workflows/deploy.yml
.gitea/workflows/rollback.yml
```
Review the runner label in both files:
```yaml
runs-on: forgeflow-production
```
Replace it with the exact label of the trusted runner that can reach the target
server environment. Commit and push these workflow files before running the
deployment preflight.
The workflows accept only controlled inputs:
```text
environment
commit_sha or target_sha
request_id
```
ForgeFlow creates the `request_id` automatically so desktop diagnostics,
Actions output and server status can be correlated without exposing a secret.
---
## Part 4 — Prepare the server and trusted runner
The example implementation targets a dedicated Git checkout deployed with
Docker Compose. Adapt the allowlisted target values, not the security model.
### 1. Confirm the server prerequisites
On the target server, verify:
```bash
git --version
docker --version
docker compose version
curl --version
flock --version
```
The application checkout must already exist and have a working `origin` that the
server can fetch without interactive prompts.
Example:
```text
/srv/YOUR-APP
/srv/YOUR-APP/compose.yml
```
### 2. Install the target configuration
Copy the template:
```bash
sudo install -d -o root -g root -m 0755 /etc/forgeflow
sudo install -o root -g root -m 0640 \
examples/server/forgeflow-targets.conf \
/etc/forgeflow/targets.conf
```
Edit it as root:
```bash
sudo nano /etc/forgeflow/targets.conf
```
Each active line has seven pipe-separated fields:
```text
repository|environment|app_dir|branch|compose_file|healthcheck_url|status_file
```
Example:
```text
jens/my-app|staging|/srv/my-app-staging|main|/srv/my-app-staging/compose.yml|http://127.0.0.1:18080/health|/var/lib/forgeflow-status/my-app-staging.json
```
Rules:
- repository must exactly match `owner/repository` in Gitea;
- environment must exactly match the ForgeFlow profile value;
- all filesystem paths must be absolute;
- status files must stay under `/var/lib/forgeflow-status/`;
- the configuration must remain root-owned and not group/other writable.
Validate permissions:
```bash
sudo stat -c '%U %G %a %n' /etc/forgeflow/targets.conf
```
Expected owner is `root`; a mode such as `640` is appropriate.
### 3. Install the allowlisted deployment entry point
```bash
sudo install -o root -g root -m 0755 \
examples/server/forgeflow-deploy \
/usr/local/bin/forgeflow-deploy
```
The script:
- accepts only a valid repository, environment, full SHA and request ID;
- resolves the repository/environment through the root-owned target file;
- rejects unsafe paths and branches;
- prevents concurrent deployments with `flock`;
- fetches the allowed branch;
- proves that the requested SHA is an ancestor of the remote branch;
- resets only the dedicated deployment checkout;
- runs the fixed Docker Compose redeploy;
- performs repeated healthchecks;
- writes live, previous and requested SHAs atomically;
- records the correlation request ID and last exit code.
### 4. Restrict runner elevation
Copy and edit the sudoers example:
```bash
sudo install -o root -g root -m 0440 \
examples/server/forgeflow-runner.sudoers \
/etc/sudoers.d/forgeflow-runner
sudo visudo -cf /etc/sudoers.d/forgeflow-runner
```
Replace `act_runner` with the actual trusted runner account. Do not grant that
account unrestricted passwordless `sudo`, shell access or wildcard commands.
### 5. Register and start the Gitea runner
Register a dedicated trusted runner according to your Gitea instance and runner
version. Attach the exact label referenced by the workflow, for example:
```text
forgeflow-production
```
Only repositories you control should be able to schedule jobs on a runner with
production access.
---
## Part 5 — Publish server version status
The server script writes one non-secret JSON status document per environment.
Serve it over HTTPS independently of the application process so it can still
report a failed release.
Copy and adapt:
```text
examples/server/nginx-forgeflow-status.conf
```
Example URL:
```text
https://YOUR-APP-HOST/.well-known/forgeflow
```
Expected response:
```json
{
"repository": "jens/my-app",
"environment": "staging",
"request_id": "00000000-0000-0000-0000-000000000000",
"commit_sha": "0123456789abcdef0123456789abcdef01234567",
"previous_sha": "89abcdef0123456789abcdef0123456789abcdef",
"requested_sha": "0123456789abcdef0123456789abcdef01234567",
"deployed_at": "2026-07-24T12:00:00Z",
"health": "healthy",
"last_exit_code": 0
}
```
Test from the ForgeFlow desktop computer:
```powershell
Invoke-WebRequest "https://YOUR-APP-HOST/.well-known/forgeflow"
Invoke-WebRequest "https://YOUR-APP-HOST/health"
```
See [`STATUS_ENDPOINT.md`](STATUS_ENDPOINT.md) for the accepted contract.
---
## Part 6 — Create the deployment profile in ForgeFlow
Open the linked repository and add an environment.
Fill in:
```text
Profile name: Staging
Environment input: staging
Allowed branch: main
Deploy workflow: deploy.yml
Rollback workflow: rollback.yml
Status URL: https://YOUR-APP-HOST/.well-known/forgeflow
Healthcheck URL: https://YOUR-APP-HOST/health
Confirmation: enabled
```
Save the profile.
---
## Part 7 — Run Deployment preflight
Select **Preflight** on the environment card. ForgeFlow must verify:
1. local repository link;
2. valid Git working tree;
3. allowed current branch;
4. clean working tree;
5. published upstream;
6. zero commits ahead and zero behind;
7. exact local SHA exists on the allowed remote branch;
8. local deploy workflow exists;
9. remote deploy workflow exists on Gitea;
10. Gitea Actions API is readable;
11. a configured server status endpoint;
12. current status-endpoint reachability;
13. application healthcheck result when configured.
The status URL is mandatory because ForgeFlow uses it after the workflow to prove
that the server applied the exact SHA for the exact request ID. An unreachable
status document can be a warning before the very first deployment because the
server script may create it, but the operation cannot finish successfully until
the endpoint returns the requested SHA and request ID. Required failures block
the Continue button and the deployment backend repeats its own Git/SHA checks at
dispatch time.
---
## Part 8 — First safe end-to-end test
Use a staging profile first.
1. Make a harmless visible change.
2. Review the diff in ForgeFlow.
3. Enter a commit message.
4. Select **Commit & push**.
5. Confirm that Local and Gitea show the same SHA.
6. Select **Deploy SHA -> Staging**.
7. Review and continue through Deployment preflight.
8. Confirm the exact SHA.
9. Follow workflow, job and healthcheck progress.
10. Confirm that the server status endpoint reports the same full SHA.
11. Create a second harmless commit and deploy it.
12. Use **Rollback** to restore the recorded previous SHA.
Also test deliberately:
- an uncommitted local change;
- a local commit that was not pushed;
- the wrong branch;
- a missing workflow file;
- a stopped runner;
- a failed healthcheck;
- a second deployment while the lock is held.
ForgeFlow should block unsafe local states and clearly retain failed operation
metadata for diagnostics.
---
## Part 9 — Export a diagnostic bundle without sharing credentials
Open **Diagnostics**.
1. Run **System preflight**.
2. Select **Strict privacy** when sharing externally.
3. Select **Create diagnostic ZIP**.
4. Inspect the ZIP before sending it.
The bundle deliberately contains no encrypted token field and omits raw runner
logs. Before writing the ZIP, ForgeFlow runs a safety audit for known runtime
secrets, private-key markers and unredacted URL credentials. If that audit
fails, no bundle is written.
See [`DIAGNOSTICS.md`](DIAGNOSTICS.md) for the exact contents and limitations.
---
## Part 8 — Configure an Unraid server
Open **Settings → SSH / Unraid servers**. Enter the host, SSH port, username and
`/mnt/user/appdata` as the base path. Prefer a private key. Save, then run
**Test & trust** to record the server host-key fingerprint.
For an existing project, enter its current server folder name. ForgeFlow
inspects the root Git repository, tracked modifications, Compose files and
nested repositories before it permits deployment.
For a new project, use the repository name as server folder. Select the
repository Compose file or enable basic generated Compose and enter host and
container ports.
See `docs/SSH_UNRAID_DEPLOYMENT.md`.
+112
View File
@@ -0,0 +1,112 @@
# SSH / Unraid deployment
ForgeFlow 0.4 can deploy an exact Gitea commit directly to an Unraid server over SSH.
## Security model
- Enter credentials only in the local ForgeFlow desktop window.
- Prefer an Ed25519 private key over a password.
- ForgeFlow stores passwords and private-key passphrases through Electron safe storage.
- The first successful test records the SSH host-key fingerprint.
- Later connections fail closed when that fingerprint changes.
- Diagnostics redact the Gitea token, SSH password and private-key passphrase.
- ForgeFlow never sends arbitrary commands entered through the renderer. Deployment commands are assembled from validated profile fields.
## Configure the server
Open **Settings → SSH / Unraid servers → Add server**.
Typical Unraid values:
```text
Name: Unraid
Host: 192.168.1.10
Port: 22
Username: root
Base path: /mnt/user/appdata
Auth: Private key
```
Save the server, then choose **Test & trust**. ForgeFlow verifies SSH, Git and Docker Compose and records the host-key fingerprint.
## Existing application folder
Create a deployment profile and choose **SSH / Unraid**.
For an existing folder:
```text
Server folder: lumaops
Remote path: /mnt/user/appdata/lumaops
Compose file: docker-compose.yml
```
ForgeFlow inspects the folder before deployment. An existing deployment is adopted only when the project root is a Git working tree. Tracked server-side changes block deployment. Untracked runtime paths such as `.env`, `appdata`, `data`, `logs`, `config` and `compose.override.yml` remain untouched by `git reset --hard`.
Keep the root `.git` directory. It is used to verify the exact commit, update the working tree and roll back to the previous SHA.
Nested Git repositories are reported as warnings and are never removed automatically.
When a Dockerfile is present, preflight also inspects `.dockerignore`. It reports
whether `.git` is excluded and warns when existing preserved runtime folders or
nested repositories would still be sent as Docker build context. Fix those
rules in the repository and commit them rather than changing only the live
server copy.
## New application folder
For a new project, ForgeFlow creates:
```text
/mnt/user/appdata/<repository-name>
```
The Unraid server clones the configured Git URL on the selected branch. The server therefore needs access to that repository, normally through an SSH deploy key or an existing trusted Gitea SSH identity.
Two Compose modes are available:
1. **Use repository Compose file** — recommended for real applications. Keep ports, volumes, devices, networks and Unraid labels version-controlled.
2. **Generate basic ForgeFlow Compose** — suitable for a simple Dockerfile-based application. ForgeFlow asks for host port, container port, service/container name, Web UI URL and icon URL and writes `.forgeflow/compose.forgeflow.yml`.
Generated Compose deliberately stays minimal. Projects requiring USB devices, GPU access, custom networks, secrets or multiple services should provide their own Compose file.
## Deployment sequence
1. Verify that the local repository is clean, on the allowed branch and fully synchronized with Gitea.
2. Verify that the exact requested SHA exists on `origin/<branch>`.
3. Verify the repository Compose file or Dockerfile locally.
4. Connect through pinned SSH.
5. Inspect the target folder.
6. Refuse tracked server-only modifications.
7. Clone when the folder does not exist.
8. Fetch the configured branch without allowing interactive credential prompts.
9. Verify again on the server that the requested full SHA belongs to `origin/<branch>`.
10. Save the current SHA as the rollback target.
11. Reset the working tree to the exact requested SHA.
12. Validate the selected Compose file.
13. Run `docker compose up -d --build --remove-orphans`.
14. Store non-secret state under `.forgeflow/` and run the configured healthcheck.
## Folder names
The default folder is the repository name. Existing deployments can keep another folder name by entering it explicitly in the profile. ForgeFlow does not rename populated application folders automatically because Docker paths, scripts and external integrations may depend on them.
A later controlled migration can align names after a successful backup and downtime window.
## Rollback
After a successful deployment, the previous SHA is stored in:
```text
.forgeflow/previous-sha
```
Rollback is accepted only for the exact SHA currently recorded as the previous
deployment. ForgeFlow rechecks that SHA against the configured Gitea branch,
refuses tracked server-side changes, resets the same working tree, runs Docker
Compose again and repeats the healthcheck. The version that was live before the
rollback becomes the new rollback target.
## Before the first real deployment
Back up the application folder and its persistent data. Run **Preflight** and resolve every failed check. Warnings, such as a nested Git repository, should be reviewed but do not automatically delete or modify anything.
+59
View File
@@ -0,0 +1,59 @@
# Server status endpoint contract
A workflow can report success while the wrong application version is running.
ForgeFlow therefore supports a small server-side endpoint that independently
reports the deployed commit.
## Canonical response
```json
{
"repository": "jens/example-app",
"environment": "production",
"request_id": "3a6ed71c-d52d-4d8d-9678-96e0c9456a81",
"commit_sha": "0123456789abcdef0123456789abcdef01234567",
"previous_sha": "89abcdef0123456789abcdef0123456789abcdef",
"requested_sha": "0123456789abcdef0123456789abcdef01234567",
"deployed_at": "2026-07-24T13:00:00Z",
"health": "healthy",
"last_exit_code": 0
}
```
Required for exact version verification:
- `commit_sha`: full 4064 character hexadecimal commit identity.
Recommended:
- `previous_sha`: previous successful commit used by rollback;
- `requested_sha`: SHA requested by the latest deployment attempt;
- `request_id`: ForgeFlow operation correlation identifier;
- `deployed_at`: ISO-8601 timestamp;
- `health`: `healthy`, `deploying` or `unhealthy`;
- `last_exit_code`: server entry-point result, with `0` for success;
- `repository` and `environment`: useful for human consistency checks.
ForgeFlow also accepts `commitSha`, `sha`, `previousSha`, `requestId` and nested
`version.sha`, but canonical snake-case fields are preferred.
## Isolation
Serve the endpoint independently from the deployed application when practical.
A static JSON file exposed by the reverse proxy remains readable when the
application fails to boot. The included deployment script writes it atomically.
The JSON file is non-secret and can be served read-only. Do not include tokens,
host credentials, environment variables, registry secrets or stack traces.
## Profile configuration
Set both URLs when available:
- **Status URL**: returns this document and exact live SHA;
- **Healthcheck URL**: returns a successful HTTP status only when the application
is operational.
After an Actions run succeeds, ForgeFlow checks both. It marks the operation
failed when the healthcheck is unhealthy or the server reports another SHA than
the requested deployment.
+99
View File
@@ -0,0 +1,99 @@
# Stitch review and design corrections
## What worked well
The Stitch export established a strong visual starting point:
- A restrained graphite theme suitable for long sessions.
- Compact desktop density.
- Clear technical typography.
- Useful deployment progress and failure concepts.
- A credible developer-tool tone without excessive decoration.
- Good use of green, amber and red for operational state.
## What was changed
### 1. From IDE shell to release cockpit
The export contained navigation for Editor, Monitoring and Extensions. Those features would blur the product into an incomplete IDE. ForgeFlow instead complements the user's existing editor and terminal.
The product boundary is now:
```text
Understand repository state -> perform safe Git action -> release exact version
```
### 2. One navigation model
The mock-ups mixed a top product navigation with a broad left application navigation. The implementation uses:
- A compact top bar for global search, identity, refresh and theme.
- A left rail for Overview, Deployments, Settings and repositories.
- Repository tabs only inside the selected project.
### 3. Operational cards instead of generic statistics
CPU, queue or server graphs are not useful unless ForgeFlow becomes a monitoring suite. The overview now answers:
- Which projects have local changes?
- Which commits are not pushed?
- Which repositories are behind or conflicted?
- Which exact commits are ready to deploy?
### 4. Persistent Local -> Gitea -> Server rail
The most important state was made visible at the top of every repository workspace. The user no longer needs to infer synchronization from several unrelated badges.
### 5. Contextual action panel
The right panel now changes with state:
- Link or clone.
- Resolve conflict.
- Commit and push.
- Fast-forward synchronize.
- Push commits.
- Configure deployment.
- Deploy exact SHA.
- Explain the blocking error.
Only one action is visually dominant.
### 6. Diff viewer, not editor
ForgeFlow displays changed files and diffs, but deliberately opens the real project folder for editing. This avoids duplicating editor features and keeps the application technically realistic.
### 7. Safer deployment language
A generic **Deploy** button can hide too much. ForgeFlow displays the exact action:
```text
Deploy b82f91a -> Production
```
The confirmation state shows the repository, branch, full SHA and workflow file.
### 8. Desktop behavior
The implementation adds details that static screens could not provide:
- Native directory selection.
- External-link restrictions.
- Keyboard shortcut for global search.
- Ctrl/Cmd+Enter for commit and push.
- Resizable desktop layout.
- Offline and error handling foundations.
- Secure process boundary between UI and system operations.
## Visual direction retained
The implementation intentionally keeps:
- Deep neutral background and panels.
- Blue primary actions.
- Green synchronization and health.
- Amber pending work.
- Red actual failures and conflicts.
- Compact status badges.
- Monospace only for branches, commits, paths and logs.
- Minimal decorative effects.
+106
View File
@@ -0,0 +1,106 @@
# Test matrix
## Automated in v0.4.0
The suite contains 59 passing tests.
### Git and repository behavior
- porcelain v2 ordinary and rename parsing;
- HTTPS and SCP-style remote matching;
- real temporary bare remote: status, diff, selected commit and push;
- real temporary bare remote: commit-only, branch creation/publication and
remote-SHA ancestry verification;
- real stash creation, listing, pop and untracked-file restoration;
- repository monitor baseline, change detection and pause/resume;
- safe repository folder-name derivation from HTTPS and SSH clone URLs;
- automatic target construction beneath the project root;
- missing, empty and matching-checkout clone target handling;
- different repository, ordinary non-empty folder and file conflict rejection.
### Gitea and deployment behavior
- Gitea URL/credential validation;
- Actions run normalization across payload shapes;
- optional query-filter compatibility retry;
- runs-to-tasks fallback;
- newest matching run selection;
- repository workflow contents lookup and 404 behavior;
- deployment terminal-status mapping;
- controlled dispatch inputs that cannot be overridden by profile data;
- exact post-workflow SHA and request-ID verification;
- rollback input allowlisting and exact current previous-SHA enforcement;
- complete deployment preflight with Git, workflow, Actions, status and health
mocks.
### Security and diagnostics
- repository path traversal and absolute-path rejection;
- workflow filename, branch, environment and full-SHA validation;
- clone protocol and embedded-password rejection;
- runtime token, authorization, query token, URL credential and private-key
redaction;
- camelCase and nested sensitive-key removal;
- home-path aliasing;
- deterministic strict-privacy identifier hashing;
- required versus optional preflight blocking behavior;
- system preflight before credentials are entered;
- structured JSONL diagnostic writes;
- support-bundle strict privacy and secret exclusion;
- ZIP structure, deflate payloads and CRC validation.
- Windows npm command-shim discovery through `npm_execpath` and `cmd.exe`;
- normal direct npm discovery on non-Windows systems.
## Static source quality gate
`npm run verify` checks:
- all required source, documentation and server-template files;
- JavaScript syntax across the project;
- package version and required scripts;
- desktop packaging metadata and icons;
- Bash syntax for the server entry point;
- status JSON parsing;
- required setup-guide sections;
- renderer entry hooks.
## Manual before a real production release
- setup wizard against the installed Gitea version;
- repository discovery on the target Windows system;
- token persistence through Windows credential protection;
- HTTPS and/or SSH Git authentication;
- actual Actions dispatch, run resolution and job visibility;
- runner label and repository trust scope;
- server target-file ownership/mode enforcement;
- status endpoint through the real reverse proxy;
- deployment lock, failed healthcheck and rollback;
- diagnostic ZIP inspection after a deliberately failed deployment;
- unsigned installer and portable build on Windows;
- keyboard-only and screen-reader smoke test.
## Renderer smoke target
The standalone demo should be checked at minimum at:
- 1120 × 720;
- 1440 × 900;
- 1920 × 1080.
Required views now include setup readiness, dashboard, repository workspace,
deployment preflight, active run, success/failure and Diagnostics.
### v0.4 additions
- bounded independently scrollable changed-file layout;
- explicit commit-message and selection readiness contract;
- ITWorx.tech asset integration;
- semantic update-version comparison;
- exact-SHA Gitea update manifest lookup;
- update repository path-injection rejection;
- SSH host-key fingerprint helper;
- remote shell quoting;
- Unraid folder and Compose path escape rejection;
- server inspection payload decoding;
- SSH deployment preflight summary behavior.
+55
View File
@@ -0,0 +1,55 @@
# Updating ForgeFlow on Windows
ForgeFlow stores its local token, server credentials, repository mappings,
preferences, deployment profiles, diagnostics and operation history outside the
source directory.
## Manual update to v0.4.0
1. Close ForgeFlow.
2. Extract the v0.4.0 update package.
3. Copy the contents of its `ForgeFlow` folder over the existing source folder.
4. Do not create `ForgeFlow\ForgeFlow`.
5. Open PowerShell in the existing folder.
6. Run:
```powershell
Set-ExecutionPolicy -Scope Process Bypass
.\update-windows.ps1
```
The script installs the new `ssh2` dependency, runs the environment doctor,
verifies the source and executes all tests before starting ForgeFlow.
## Built-in updates after v0.4.0
Open **Settings → ForgeFlow updates**.
The default source is:
```text
Gitea instance: the instance already configured in ForgeFlow
Repository: Jens/ForgeFlow
Branch: main
```
The repository must contain a newer semantic version in `package.json`.
Choose:
1. **Check now**
2. **Download update**
3. **Apply & restart**
The source updater downloads the exact branch commit, records a SHA-256 checksum,
backs up the installed source, applies the archive, runs `npm install` and
`npm run check`, and restarts ForgeFlow. When validation fails it restores the
previous source and starts that version again.
The update log is written beneath ForgeFlow's local user-data `updates` folder
and does not contain the Gitea token.
The updater deliberately checks the semantic version stored in the remote
`package.json`. Merely pushing a new commit without increasing that version does
not present an update. Publish the complete validated ForgeFlow source to the
configured repository and bump the version for every release.
Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB