Update
This commit is contained in:
@@ -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`.
|
||||
Reference in New Issue
Block a user