222 lines
8.1 KiB
Markdown
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.
|