486 lines
13 KiB
Markdown
486 lines
13 KiB
Markdown
# 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`.
|