hygiene: prepare ForgeFlow for public release
Managed validation / full (pull_request) Successful in 27s

This commit is contained in:
NuklearRabbit
2026-09-02 23:37:30 +02:00
parent 0a8a10df1b
commit dec3b79793
11 changed files with 21 additions and 19 deletions
+2
View File
@@ -21,6 +21,8 @@ concurrency:
jobs: jobs:
full: full:
name: full name: full
# Public fork code must never execute automatically on the private runner.
if: ${{ gitea.event_name != 'pull_request' || gitea.event.pull_request.head.repo.full_name == gitea.repository }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 30 timeout-minutes: 30
steps: steps:
+1 -1
View File
@@ -2,7 +2,7 @@
ForgeFlow's detailed security model is documented in [`docs/SECURITY.md`](docs/SECURITY.md). ForgeFlow's detailed security model is documented in [`docs/SECURITY.md`](docs/SECURITY.md).
Report suspected vulnerabilities privately to the repository owner. Do not publish Gitea tokens, SSH credentials, update-signing material, private server addresses, support bundles containing sensitive data or other operational secrets in a public issue. Report suspected vulnerabilities privately to `security@itworx.tech`. Do not publish Gitea tokens, SSH credentials, update-signing material, private server addresses, support bundles containing sensitive data or other operational secrets in a public issue.
For a useful report, include the affected ForgeFlow version/commit, component, minimal reproduction steps, expected and observed behaviour and security impact. Use sanitized or synthetic repository/server data whenever possible. For a useful report, include the affected ForgeFlow version/commit, component, minimal reproduction steps, expected and observed behaviour and security impact. Use sanitized or synthetic repository/server data whenever possible.
+1 -1
View File
@@ -3,7 +3,7 @@
1. Close ForgeFlow completely. 1. Close ForgeFlow completely.
2. Extract `ForgeFlow-0.4.0-update-from-0.3.2.zip`. 2. Extract `ForgeFlow-0.4.0-update-from-0.3.2.zip`.
3. Copy the contents of the included `ForgeFlow` folder into your existing 3. Copy the contents of the included `ForgeFlow` folder into your existing
`C:\Users\Jens\dyad-apps\ForgeFlow` folder and replace existing files. `C:\Users\your-name\Apps\ForgeFlow` folder and replace existing files.
4. Do not create a nested `ForgeFlow\ForgeFlow` folder. 4. Do not create a nested `ForgeFlow\ForgeFlow` folder.
5. Open Windows PowerShell in the existing ForgeFlow folder and run: 5. Open Windows PowerShell in the existing ForgeFlow folder and run:
+2 -2
View File
@@ -17,9 +17,9 @@ for every repository. ForgeFlow now:
Example: Example:
```text ```text
Default project root: C:\Users\Jens\Projects Default project root: C:\Users\your-name\Projects
Gitea repository: Jens/Portfolio Gitea repository: Jens/Portfolio
Automatic target: C:\Users\Jens\Projects\Portfolio Automatic target: C:\Users\your-name\Projects\Portfolio
``` ```
A separate **Choose another location** action remains available for exceptional A separate **Choose another location** action remains available for exceptional
+2 -2
View File
@@ -53,13 +53,13 @@ The binary publisher refuses to upload when local `HEAD` differs from the config
Extract the complete source ZIP so this file exists: Extract the complete source ZIP so this file exists:
```text ```text
C:\Users\Jens\Downloads\ForgeFlow-<version>\ForgeFlow\package.json C:\Users\your-name\Downloads\ForgeFlow-<version>\ForgeFlow\package.json
``` ```
Run: Run:
```powershell ```powershell
cd C:\Users\Jens\Downloads\ForgeFlow-<version>\ForgeFlow cd C:\Users\your-name\Downloads\ForgeFlow-<version>\ForgeFlow
Set-ExecutionPolicy -Scope Process Bypass Set-ExecutionPolicy -Scope Process Bypass
.\Publish-ForgeFlow-Release.ps1 .\Publish-ForgeFlow-Release.ps1
``` ```
+1 -1
View File
@@ -176,7 +176,7 @@
username: "root", username: "root",
authType: "privateKey", authType: "privateKey",
basePath: "/mnt/user/appdata", basePath: "/mnt/user/appdata",
privateKeyPath: "C:\\Users\\Jens\\.ssh\\id_ed25519", privateKeyPath: "C:\\Users\\your-name\\.ssh\\id_ed25519",
hostFingerprint: "SHA256:demo", hostFingerprint: "SHA256:demo",
hasPassword: false, hasPassword: false,
hasPassphrase: false, hasPassphrase: false,
+1 -1
View File
@@ -665,7 +665,7 @@ function createMockDeploymentBridge(context) {
async exportDiagnostics(privacyMode = "standard") { async exportDiagnostics(privacyMode = "standard") {
await wait(500); await wait(500);
return { return {
path: `C:\Users\Jens\Downloads\ForgeFlow-Diagnostics-demo.zip`, path: `C:\Users\your-name\Downloads\ForgeFlow-Diagnostics-demo.zip`,
bytes: 38221, bytes: 38221,
size: "37.3 KB", size: "37.3 KB",
sha256: "b".repeat(64), sha256: "b".repeat(64),
+1 -1
View File
@@ -29,7 +29,7 @@ function createMockRepositoryBridge(context) {
}, },
async selectKeyFile() { async selectKeyFile() {
await wait(); await wait();
return "C:\\Users\\Jens\\.ssh\\id_ed25519"; return "C:\\Users\\your-name\\.ssh\\id_ed25519";
}, },
async setupPreflight({ baseUrl, token, roots = [] }) { async setupPreflight({ baseUrl, token, roots = [] }) {
await wait(240); await wait(240);
+1 -1
View File
@@ -164,7 +164,7 @@ test('rewrites Gitea internal HTTP release URLs to the configured public origin'
return Buffer.from('asset'); return Buffer.from('asset');
}; };
await service.downloadReleaseAsset('Jens', 'ForgeFlow', 107, 412, { await service.downloadReleaseAsset('Jens', 'ForgeFlow', 107, 412, {
downloadUrl: 'http://192.168.10.150:3000/Jens/ForgeFlow/releases/download/v0.10.1/ForgeFlow.exe', downloadUrl: 'http://192.168.56.10:3000/Jens/ForgeFlow/releases/download/v0.10.1/ForgeFlow.exe',
}); });
assert.equal(requested, 'https://gitea.example.test/Jens/ForgeFlow/releases/download/v0.10.1/ForgeFlow.exe'); assert.equal(requested, 'https://gitea.example.test/Jens/ForgeFlow/releases/download/v0.10.1/ForgeFlow.exe');
}); });
+2 -2
View File
@@ -20,7 +20,7 @@ test('redacts runtime credentials, structured secrets, private keys and URL cred
test('sanitizes nested sensitive keys and aliases user paths', () => { test('sanitizes nested sensitive keys and aliases user paths', () => {
const value = { const value = {
accessToken: 'do-not-keep', accessToken: 'do-not-keep',
nested: { password: 'do-not-keep-either', path: 'C:\\Users\\Jens\\Projects\\ForgeFlow' }, nested: { password: 'do-not-keep-either', path: 'C:\\Users\\example-user\\Projects\\ForgeFlow' },
home: '/home/jens/projects/forgeflow' home: '/home/jens/projects/forgeflow'
}; };
const sanitized = sanitizeForDiagnostics(value, { homeDir: '/home/jens', cwd: '/work/ForgeFlow' }); const sanitized = sanitizeForDiagnostics(value, { homeDir: '/home/jens', cwd: '/work/ForgeFlow' });
@@ -48,7 +48,7 @@ test('strict privacy redacts private addresses, infrastructure URLs and server p
}); });
test('path aliasing handles slash variants', () => { test('path aliasing handles slash variants', () => {
const result = pathAlias('C:\\Users\\Jens\\src and C:/Users/Jens/src', { homeDir: 'C:\\Users\\Jens', cwd: 'D:\\ForgeFlow' }); const result = pathAlias('C:\\Users\\example-user\\src and C:/Users/example-user/src', { homeDir: 'C:\\Users\\example-user', cwd: 'D:\\ForgeFlow' });
assert.doesNotMatch(result, /Users[\\/]Jens/); assert.doesNotMatch(result, /Users[\\/]Jens/);
assert.match(result, /<HOME>/); assert.match(result, /<HOME>/);
}); });
+7 -7
View File
@@ -121,10 +121,10 @@ test("server pull prefers the linked checkout origin over stale detected SSH end
const repository = { const repository = {
fullName: "Jens/Portfolio", fullName: "Jens/Portfolio",
localStatus: { remoteUrl: "git@gitea.itworx.tech:Jens/Portfolio.git" }, localStatus: { remoteUrl: "git@gitea.itworx.tech:Jens/Portfolio.git" },
sshUrl: "ssh://git@192.168.10.150:222/Jens/Portfolio.git", sshUrl: "ssh://git@192.168.56.10:222/Jens/Portfolio.git",
preferredCloneUrl: "ssh://git@192.168.10.150:222/Jens/Portfolio.git", preferredCloneUrl: "ssh://git@192.168.56.10:222/Jens/Portfolio.git",
}; };
const profile = { cloneUrl: "ssh://git@192.168.10.150:222/Jens/Portfolio.git" }; const profile = { cloneUrl: "ssh://git@192.168.56.10:222/Jens/Portfolio.git" };
assert.equal(service.serverGitRemote(repository, profile), "git@gitea.itworx.tech:Jens/Portfolio.git"); assert.equal(service.serverGitRemote(repository, profile), "git@gitea.itworx.tech:Jens/Portfolio.git");
assert.deepEqual(service.serverGitHost(repository, profile), { host: "gitea.itworx.tech", port: 22 }); assert.deepEqual(service.serverGitHost(repository, profile), { host: "gitea.itworx.tech", port: 22 });
@@ -894,7 +894,7 @@ test("DockerMan metadata uses dockerman labels, a template WebUI and lowercase-s
remoteFolder: "Portfolio", remoteFolder: "Portfolio",
environment: "production", environment: "production",
hostPort: 5150, hostPort: 5150,
webUiUrl: "http://192.168.10.150:5150/admin", webUiUrl: "http://192.168.56.10:5150/admin",
dockerShell: "/bin/sh", dockerShell: "/bin/sh",
}, },
{ name: "Portfolio" }, { name: "Portfolio" },
@@ -927,7 +927,7 @@ test("DockerMan integration writes a persistent template fallback and invalidate
remoteFolder: "Portfolio", remoteFolder: "Portfolio",
environment: "production", environment: "production",
hostPort: 5150, hostPort: 5150,
webUiUrl: "http://192.168.10.150:5150/", webUiUrl: "http://192.168.56.10:5150/",
dockerShell: "/bin/sh", dockerShell: "/bin/sh",
manageDockerMan: true, manageDockerMan: true,
generatedCompose: true, generatedCompose: true,
@@ -1124,7 +1124,7 @@ test("existing Unraid deployment discovery derives profile values from Docker, C
defaultBranch: "main", defaultBranch: "main",
sshUrl: "ssh://git@gitea/Jens/blockpilot-autonomous.git", sshUrl: "ssh://git@gitea/Jens/blockpilot-autonomous.git",
}, },
server: { id: "unraid", host: "192.168.10.150" }, server: { id: "unraid", host: "192.168.56.10" },
remoteFolder: "blockpilot-autonomous", remoteFolder: "blockpilot-autonomous",
remotePath: "/mnt/user/appdata/blockpilot-autonomous", remotePath: "/mnt/user/appdata/blockpilot-autonomous",
payload: { payload: {
@@ -1399,7 +1399,7 @@ test("push bundle preflight does not require Git or Gitea credentials on Unraid"
getServer: () => ({ getServer: () => ({
id: "unraid", id: "unraid",
name: "Unraid", name: "Unraid",
host: "192.168.10.150", host: "192.168.56.10",
port: 22, port: 22,
username: "root", username: "root",
basePath: "/mnt/user/appdata", basePath: "/mnt/user/appdata",