Files
ForgeFlow/docs/ARCHITECTURE.md
T
2026-07-24 20:29:23 +02:00

222 lines
8.1 KiB
Markdown

# 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.