vibe-forge 0.4.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/commands/clear-attention.md +63 -63
- package/.claude/commands/compact-context.md +52 -0
- package/.claude/commands/configure-vcs.md +102 -102
- package/.claude/commands/forge.md +218 -171
- package/.claude/commands/need-help.md +77 -77
- package/.claude/commands/update-status.md +64 -64
- package/.claude/commands/worker-loop.md +106 -106
- package/.claude/hooks/worker-loop.js +217 -187
- package/.claude/scripts/setup-worker-loop.sh +45 -45
- package/.claude/settings.json +89 -0
- package/LICENSE +21 -21
- package/README.md +253 -232
- package/agents/aegis/personality.md +303 -269
- package/agents/anvil/personality.md +278 -240
- package/agents/architect/personality.md +260 -234
- package/agents/crucible/personality.md +362 -309
- package/agents/crucible-x/personality.md +210 -0
- package/agents/ember/personality.md +293 -265
- package/agents/flux/personality.md +248 -0
- package/agents/furnace/personality.md +342 -291
- package/agents/herald/personality.md +249 -247
- package/agents/loki/personality.md +108 -0
- package/agents/oracle/personality.md +284 -0
- package/agents/pixel/personality.md +140 -0
- package/agents/planning-hub/personality.md +473 -251
- package/agents/scribe/personality.md +253 -251
- package/agents/slag/personality.md +268 -0
- package/agents/temper/personality.md +270 -0
- package/bin/cli.js +372 -325
- package/bin/dashboard/api/agents.js +333 -0
- package/bin/dashboard/api/dispatch.js +507 -0
- package/bin/dashboard/api/tasks.js +416 -0
- package/bin/dashboard/public/assets/index-BpHfsx1r.js +2 -0
- package/bin/dashboard/public/assets/index-QODv4Zn9.css +1 -0
- package/bin/dashboard/public/index.html +14 -0
- package/bin/dashboard/server.js +645 -0
- package/bin/forge-daemon.sh +477 -851
- package/bin/forge-setup.sh +661 -645
- package/bin/forge-spawn.sh +164 -164
- package/bin/forge.cmd +83 -83
- package/bin/forge.sh +566 -387
- package/bin/lib/agents.sh +177 -177
- package/bin/lib/check-aliases.js +50 -0
- package/bin/lib/colors.sh +44 -44
- package/bin/lib/config.sh +347 -313
- package/bin/lib/constants.sh +241 -206
- package/bin/lib/daemon/budgets.sh +107 -0
- package/bin/lib/daemon/dependencies.sh +146 -0
- package/bin/lib/daemon/display.sh +128 -0
- package/bin/lib/daemon/notifications.sh +273 -0
- package/bin/lib/daemon/routing.sh +93 -0
- package/bin/lib/daemon/state.sh +163 -0
- package/bin/lib/daemon/sync.sh +103 -0
- package/bin/lib/database.sh +357 -305
- package/bin/lib/frontmatter.js +106 -0
- package/bin/lib/heimdall-setup.js +113 -0
- package/bin/lib/heimdall.js +265 -0
- package/bin/lib/json.sh +264 -258
- package/bin/lib/terminal.js +452 -446
- package/bin/lib/util.sh +126 -126
- package/bin/lib/vcs.js +349 -349
- package/config/agent-manifest.yaml +237 -243
- package/config/agents.json +207 -132
- package/config/task-template.md +159 -87
- package/config/task-types.yaml +111 -106
- package/config/templates/handoff-template.md +40 -0
- package/context/agent-overrides/README.md +41 -0
- package/context/architecture.md +42 -0
- package/context/modern-conventions.md +129 -129
- package/context/project-context-template.md +122 -122
- package/docs/agents.md +473 -409
- package/docs/architecture.md +194 -162
- package/docs/commands.md +451 -388
- package/docs/security.md +195 -144
- package/package.json +77 -50
- package/.claude/settings.local.json +0 -33
- package/agents/forge-master/capabilities.md +0 -144
- package/agents/forge-master/context-template.md +0 -128
- package/agents/forge-master/personality.md +0 -138
- package/agents/sentinel/personality.md +0 -194
- package/context/forge-state.yaml +0 -19
- package/docs/TODO.md +0 -150
- package/docs/getting-started.md +0 -243
- package/docs/npm-publishing.md +0 -95
- package/docs/workflows/README.md +0 -32
- package/docs/workflows/azure-devops.md +0 -108
- package/docs/workflows/bitbucket.md +0 -104
- package/docs/workflows/git-only.md +0 -130
- package/docs/workflows/gitea.md +0 -168
- package/docs/workflows/github.md +0 -103
- package/docs/workflows/gitlab.md +0 -105
- package/docs/workflows.md +0 -454
- package/tasks/completed/ARCH-001-duplicate-agent-config.md +0 -121
- package/tasks/completed/ARCH-002-mixed-bash-node-implementation.md +0 -88
- package/tasks/completed/ARCH-003-worker-loop-hook-duplication.md +0 -77
- package/tasks/completed/ARCH-009-test-organization.md +0 -78
- package/tasks/completed/ARCH-011-jq-vs-nodejs-json.md +0 -94
- package/tasks/completed/ARCH-012-tmp-files-in-root.md +0 -71
- package/tasks/completed/ARCH-013-exit-code-constants.md +0 -65
- package/tasks/completed/ARCH-014-sed-incompatibility.md +0 -96
- package/tasks/completed/ARCH-015-docs-todo-tracking.md +0 -83
- package/tasks/completed/CLEAN-001.md +0 -38
- package/tasks/completed/CLEAN-003.md +0 -47
- package/tasks/completed/CLEAN-004.md +0 -56
- package/tasks/completed/CLEAN-005.md +0 -75
- package/tasks/completed/CLEAN-006.md +0 -47
- package/tasks/completed/CLEAN-007.md +0 -34
- package/tasks/completed/CLEAN-008.md +0 -49
- package/tasks/completed/CLEAN-012.md +0 -58
- package/tasks/completed/CLEAN-013.md +0 -45
- package/tasks/completed/SEC-001-sql-injection-fix.md +0 -58
- package/tasks/completed/SEC-002-notification-injection-fix.md +0 -45
- package/tasks/completed/SEC-003-eval-injection-fix.md +0 -54
- package/tasks/completed/SEC-004-pid-race-condition-fix.md +0 -49
- package/tasks/completed/SEC-005-worker-loop-path-fix.md +0 -51
- package/tasks/completed/SEC-006-eval-agent-names.md +0 -55
- package/tasks/completed/SEC-007-spawn-escaping.md +0 -67
- package/tasks/pending/ARCH-004-git-bash-detection-duplication.md +0 -72
- package/tasks/pending/ARCH-005-missing-src-directory.md +0 -95
- package/tasks/pending/ARCH-006-task-template-location.md +0 -64
- package/tasks/pending/ARCH-007-daemon-monolith.md +0 -91
- package/tasks/pending/ARCH-008-forge-master-vs-hub.md +0 -81
- package/tasks/pending/ARCH-010-missing-index-files.md +0 -84
- package/tasks/pending/CLEAN-002.md +0 -29
- package/tasks/pending/CLEAN-009.md +0 -31
- package/tasks/pending/CLEAN-010.md +0 -30
- package/tasks/pending/CLEAN-011.md +0 -30
- package/tasks/pending/CLEAN-014.md +0 -32
- package/tasks/review/task-001.md +0 -78
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: CLEAN-004
|
|
3
|
-
title: "SQL injection vulnerability in database.sh - db_get_agents_by_status"
|
|
4
|
-
type: code-quality
|
|
5
|
-
priority: high
|
|
6
|
-
assigned_to: aegis
|
|
7
|
-
created_at: 2026-01-15T17:00:00Z
|
|
8
|
-
created_by: sentinel-review
|
|
9
|
-
completed_at: 2026-01-16T00:00:00Z
|
|
10
|
-
completed_by: furnace
|
|
11
|
-
status: duplicate
|
|
12
|
-
duplicate_of: SEC-001
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## Summary
|
|
16
|
-
The `db_get_agents_by_status` function in database.sh does not escape its input parameter before using it in a SQL query. While other functions in the same file use `db_escape()`, this one does not.
|
|
17
|
-
|
|
18
|
-
## Affected Files/Lines
|
|
19
|
-
- `bin/lib/database.sh:213-216` - db_get_agents_by_status function
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
db_get_agents_by_status() {
|
|
23
|
-
local status="$1"
|
|
24
|
-
sqlite3 "$FORGE_DB" "SELECT agent FROM agent_status WHERE status = '$status';"
|
|
25
|
-
}
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
The `$status` parameter is used directly without escaping.
|
|
29
|
-
|
|
30
|
-
## Remediation
|
|
31
|
-
Apply the same pattern used by other functions in the file:
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
db_get_agents_by_status() {
|
|
35
|
-
local status="$1"
|
|
36
|
-
# SECURITY: Escape status to prevent SQL injection
|
|
37
|
-
status=$(db_escape "$status")
|
|
38
|
-
sqlite3 "$FORGE_DB" "SELECT agent FROM agent_status WHERE status = '$status';"
|
|
39
|
-
}
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## Acceptance Criteria
|
|
43
|
-
- [x] `db_get_agents_by_status` uses `db_escape()` for the status parameter
|
|
44
|
-
- [x] All other functions reviewed to ensure consistent escaping
|
|
45
|
-
- [x] No direct string interpolation of untrusted input in SQL queries
|
|
46
|
-
|
|
47
|
-
## Resolution
|
|
48
|
-
**DUPLICATE OF SEC-001** - This issue was already fixed as part of the SEC-001 SQL injection remediation. The current code in `bin/lib/database.sh` (lines 213-218) already includes the `db_escape` call:
|
|
49
|
-
```bash
|
|
50
|
-
db_get_agents_by_status() {
|
|
51
|
-
local status="$1"
|
|
52
|
-
# SECURITY: Escape status to prevent SQL injection
|
|
53
|
-
status=$(db_escape "$status")
|
|
54
|
-
sqlite3 "$FORGE_DB" "SELECT agent FROM agent_status WHERE status = '$status';"
|
|
55
|
-
}
|
|
56
|
-
```
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: CLEAN-005
|
|
3
|
-
title: "SQL injection vulnerability in database.sh - db_record_status_history"
|
|
4
|
-
type: code-quality
|
|
5
|
-
priority: high
|
|
6
|
-
assigned_to: aegis
|
|
7
|
-
created_at: 2026-01-15T17:00:00Z
|
|
8
|
-
created_by: sentinel-review
|
|
9
|
-
completed_at: 2026-01-16T00:00:00Z
|
|
10
|
-
completed_by: furnace
|
|
11
|
-
status: duplicate
|
|
12
|
-
duplicate_of: SEC-001
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## Summary
|
|
16
|
-
The `db_record_status_history` function does not escape its input parameters before using them in SQL. This is inconsistent with `db_upsert_agent_status` which properly escapes all inputs.
|
|
17
|
-
|
|
18
|
-
## Affected Files/Lines
|
|
19
|
-
- `bin/lib/database.sh:237-246` - db_record_status_history function
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
db_record_status_history() {
|
|
23
|
-
local agent="$1"
|
|
24
|
-
local status="$2"
|
|
25
|
-
local task="$3"
|
|
26
|
-
|
|
27
|
-
sqlite3 "$FORGE_DB" <<SQL
|
|
28
|
-
INSERT INTO status_history (agent, status, task)
|
|
29
|
-
VALUES ('$agent', '$status', '$task');
|
|
30
|
-
SQL
|
|
31
|
-
}
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
None of the parameters are escaped.
|
|
35
|
-
|
|
36
|
-
## Remediation
|
|
37
|
-
Apply escaping to all parameters:
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
db_record_status_history() {
|
|
41
|
-
local agent="$1"
|
|
42
|
-
local status="$2"
|
|
43
|
-
local task="$3"
|
|
44
|
-
|
|
45
|
-
# SECURITY: Escape all string inputs to prevent SQL injection
|
|
46
|
-
agent=$(db_escape "$agent")
|
|
47
|
-
status=$(db_escape "$status")
|
|
48
|
-
task=$(db_escape "$task")
|
|
49
|
-
|
|
50
|
-
sqlite3 "$FORGE_DB" <<SQL
|
|
51
|
-
INSERT INTO status_history (agent, status, task)
|
|
52
|
-
VALUES ('$agent', '$status', '$task');
|
|
53
|
-
SQL
|
|
54
|
-
}
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
## Acceptance Criteria
|
|
58
|
-
- [x] All parameters in `db_record_status_history` are escaped
|
|
59
|
-
- [x] Function follows the same security pattern as `db_upsert_agent_status`
|
|
60
|
-
|
|
61
|
-
## Resolution
|
|
62
|
-
**DUPLICATE OF SEC-001** - This issue was already fixed as part of the SEC-001 SQL injection remediation. The current code in `bin/lib/database.sh` (lines 243-257) already includes the `db_escape` calls:
|
|
63
|
-
```bash
|
|
64
|
-
db_record_status_history() {
|
|
65
|
-
local agent="$1"
|
|
66
|
-
local status="$2"
|
|
67
|
-
local task="$3"
|
|
68
|
-
|
|
69
|
-
# SECURITY: Escape all inputs to prevent SQL injection
|
|
70
|
-
agent=$(db_escape "$agent")
|
|
71
|
-
status=$(db_escape "$status")
|
|
72
|
-
task=$(db_escape "$task")
|
|
73
|
-
...
|
|
74
|
-
}
|
|
75
|
-
```
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: CLEAN-006
|
|
3
|
-
title: "Missing error handling in forge-setup.sh sed commands"
|
|
4
|
-
type: code-quality
|
|
5
|
-
priority: low
|
|
6
|
-
assigned_to: furnace
|
|
7
|
-
created_at: 2026-01-15T17:00:00Z
|
|
8
|
-
created_by: sentinel-review
|
|
9
|
-
completed_at: 2026-01-16T00:00:00Z
|
|
10
|
-
completed_by: furnace
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Summary
|
|
14
|
-
The forge-setup.sh script uses sed commands with error suppression (`2>/dev/null || true`) but this makes it hard to diagnose setup issues. Some sed commands may silently fail without updating the config correctly.
|
|
15
|
-
|
|
16
|
-
## Affected Files/Lines
|
|
17
|
-
- `bin/forge-setup.sh:205` - `sed -i 's/"validated": false/"validated": true/' "$config_file" 2>/dev/null || true`
|
|
18
|
-
- `bin/forge-setup.sh:249` - sed for terminal_type
|
|
19
|
-
- `bin/forge-setup.sh:291` - sed for daemon_enabled
|
|
20
|
-
- `bin/forge-setup.sh:334` - sed for worker_loop_enabled
|
|
21
|
-
- `bin/forge-setup.sh:451-459` - Multiple sed commands for project context
|
|
22
|
-
|
|
23
|
-
## Remediation
|
|
24
|
-
1. Consider using jq for JSON modifications instead of sed (more robust)
|
|
25
|
-
2. Or at minimum, check if the expected changes were made and warn if not
|
|
26
|
-
3. The `write_json_config` function in config.sh already exists and uses proper JSON parsing
|
|
27
|
-
|
|
28
|
-
## Acceptance Criteria
|
|
29
|
-
- [x] Replace sed-based JSON modifications with jq or write_json_config
|
|
30
|
-
- [x] Failed config updates produce visible warnings
|
|
31
|
-
- [x] Config file modifications are atomic where possible
|
|
32
|
-
|
|
33
|
-
## Resolution
|
|
34
|
-
Replaced sed-based JSON modifications in `bin/forge-setup.sh` with `json_write` and `json_write_bool` functions from the new `bin/lib/json.sh` library:
|
|
35
|
-
|
|
36
|
-
1. **Line 208** (validated field): `sed_inplace` -> `json_write_bool "$config_file" "validated" true`
|
|
37
|
-
2. **Line 252** (terminal_type): Complex sed regex -> `json_write "$config_file" "terminal_type" "$terminal_choice"`
|
|
38
|
-
3. **Line 294** (daemon_enabled): Complex sed regex -> `json_write_bool "$config_file" "daemon_enabled" ...`
|
|
39
|
-
4. **Line 337** (worker_loop_enabled): Complex sed regex -> `json_write_bool "$config_file" "worker_loop_enabled" ...`
|
|
40
|
-
|
|
41
|
-
The `json_write` function (Node.js-based) provides:
|
|
42
|
-
- Proper JSON parsing and formatting
|
|
43
|
-
- Atomic file writes
|
|
44
|
-
- Clear error messages if operations fail
|
|
45
|
-
- No silent failures
|
|
46
|
-
|
|
47
|
-
The sed commands for project context template (markdown file, not JSON) remain unchanged as those use the already-improved `sed_inplace` function with proper error handling.
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: CLEAN-007
|
|
3
|
-
title: "Inconsistent decision values between shell and JS worker-loop hooks"
|
|
4
|
-
type: code-quality
|
|
5
|
-
priority: medium
|
|
6
|
-
assigned_to: furnace
|
|
7
|
-
created_at: 2026-01-15T17:00:00Z
|
|
8
|
-
created_by: sentinel-review
|
|
9
|
-
completed_at: 2026-01-16T00:00:00Z
|
|
10
|
-
completed_by: furnace
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Summary
|
|
14
|
-
The worker-loop implementations use different decision values for allowing exit:
|
|
15
|
-
- Shell version uses `"decision": "allow"`
|
|
16
|
-
- JS version uses `"decision": "approve"`
|
|
17
|
-
|
|
18
|
-
This inconsistency could cause issues if the Claude Code hook system expects a specific value.
|
|
19
|
-
|
|
20
|
-
## Affected Files/Lines
|
|
21
|
-
- `.claude/hooks/worker-loop.sh:53-54` - uses `"allow"`
|
|
22
|
-
- `.claude/hooks/worker-loop.js:106-107` - uses `"approve"`
|
|
23
|
-
|
|
24
|
-
## Remediation
|
|
25
|
-
1. Check Claude Code documentation for the expected decision values
|
|
26
|
-
2. Standardize on the correct value in all implementations
|
|
27
|
-
3. If both are valid, pick one for consistency
|
|
28
|
-
|
|
29
|
-
## Acceptance Criteria
|
|
30
|
-
- [x] Decision values are consistent across all hook implementations
|
|
31
|
-
- [x] Correct value matches Claude Code hook API specification
|
|
32
|
-
|
|
33
|
-
## Resolution
|
|
34
|
-
This issue is resolved by the removal of the shell implementation (`.claude/hooks/worker-loop.sh`) as part of ARCH-003/CLEAN-001. With only the Node.js implementation remaining, there is no longer any inconsistency. The JS version uses `"decision": "approve"` consistently throughout, and this is the value expected by the Claude Code hook API.
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: CLEAN-008
|
|
3
|
-
title: "Long function: cmd_status in forge-daemon.sh exceeds 80 lines"
|
|
4
|
-
type: code-quality
|
|
5
|
-
priority: low
|
|
6
|
-
assigned_to: furnace
|
|
7
|
-
created_at: 2026-01-15T17:00:00Z
|
|
8
|
-
created_by: sentinel-review
|
|
9
|
-
completed_at: 2026-01-16T00:00:00Z
|
|
10
|
-
completed_by: furnace
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Summary
|
|
14
|
-
The `cmd_status` function in forge-daemon.sh spans from line 618 to line 720 (over 100 lines). This function handles multiple responsibilities:
|
|
15
|
-
1. Checking daemon status
|
|
16
|
-
2. Displaying task counts
|
|
17
|
-
3. Showing attention-needed workers
|
|
18
|
-
4. Displaying worker status with staleness checks
|
|
19
|
-
5. Showing recent notifications
|
|
20
|
-
|
|
21
|
-
This violates single-responsibility principle and makes the function hard to maintain.
|
|
22
|
-
|
|
23
|
-
## Affected Files/Lines
|
|
24
|
-
- `bin/forge-daemon.sh:618-720` - cmd_status function
|
|
25
|
-
|
|
26
|
-
## Remediation
|
|
27
|
-
Extract helper functions:
|
|
28
|
-
1. `display_daemon_status()` - PID check and running/stopped status
|
|
29
|
-
2. `display_task_counts()` - Task count display from state file
|
|
30
|
-
3. `display_attention_needed()` - Attention-needed worker alerts
|
|
31
|
-
4. `display_worker_status()` - Worker status with staleness indicators
|
|
32
|
-
5. `display_recent_notifications()` - Notification log tail
|
|
33
|
-
|
|
34
|
-
## Acceptance Criteria
|
|
35
|
-
- [x] cmd_status function is under 40 lines (now ~15 lines)
|
|
36
|
-
- [x] Each extracted helper has a single clear responsibility
|
|
37
|
-
- [x] Existing functionality preserved (no behavioral changes)
|
|
38
|
-
|
|
39
|
-
## Resolution
|
|
40
|
-
Extracted the following helper functions from `cmd_status` in `bin/forge-daemon.sh`:
|
|
41
|
-
|
|
42
|
-
1. **`display_daemon_status()`** - PID check and running/stopped status display
|
|
43
|
-
2. **`display_task_counts()`** - Task count display from state file
|
|
44
|
-
3. **`display_attention_needed()`** - Attention-needed worker alerts with issues
|
|
45
|
-
4. **`get_status_icon()`** - Helper to get emoji icon for worker status
|
|
46
|
-
5. **`display_worker_status()`** - Worker status with staleness indicators
|
|
47
|
-
6. **`display_recent_notifications()`** - Notification log tail display
|
|
48
|
-
|
|
49
|
-
The main `cmd_status()` function is now ~15 lines and simply orchestrates the display by calling each helper function in order. Each helper function has a single, clear responsibility and can be tested/modified independently.
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: CLEAN-012
|
|
3
|
-
title: "Missing FORGE_DB initialization in database.sh"
|
|
4
|
-
type: code-quality
|
|
5
|
-
priority: medium
|
|
6
|
-
assigned_to: furnace
|
|
7
|
-
created_at: 2026-01-15T17:00:00Z
|
|
8
|
-
created_by: sentinel-review
|
|
9
|
-
completed_at: 2026-01-16T00:00:00Z
|
|
10
|
-
completed_by: furnace
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Summary
|
|
14
|
-
The database.sh file declares `FORGE_DB=""` at the top but relies on the calling script to set it. There's no validation that FORGE_DB is set before database operations, which could lead to confusing errors if a script forgets to set it.
|
|
15
|
-
|
|
16
|
-
## Affected Files/Lines
|
|
17
|
-
- `bin/lib/database.sh:8` - `FORGE_DB=""`
|
|
18
|
-
- `bin/forge-daemon.sh:33` - `FORGE_DB="$FORGE_ROOT/.forge/forge.db"` (sets it correctly)
|
|
19
|
-
|
|
20
|
-
## Remediation
|
|
21
|
-
Add a guard function or validation to database operations:
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
db_require_init() {
|
|
25
|
-
if [[ -z "$FORGE_DB" ]]; then
|
|
26
|
-
echo "Error: FORGE_DB not set. Call db_init with database path first." >&2
|
|
27
|
-
exit 1
|
|
28
|
-
fi
|
|
29
|
-
}
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
Or provide a db_set_path function that must be called before other operations.
|
|
33
|
-
|
|
34
|
-
## Acceptance Criteria
|
|
35
|
-
- [x] Database functions fail with clear error if FORGE_DB not initialized
|
|
36
|
-
- [x] Documentation comments explain initialization requirements
|
|
37
|
-
|
|
38
|
-
## Resolution
|
|
39
|
-
Added `db_require_init()` guard function to `bin/lib/database.sh`:
|
|
40
|
-
```bash
|
|
41
|
-
db_require_init() {
|
|
42
|
-
if [[ -z "$FORGE_DB" ]]; then
|
|
43
|
-
echo "Error: FORGE_DB not set. Set FORGE_DB path before calling database functions." >&2
|
|
44
|
-
return 1
|
|
45
|
-
fi
|
|
46
|
-
return 0
|
|
47
|
-
}
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
Added guard calls to key database functions:
|
|
51
|
-
- `db_init()` - Added guard and documentation comment
|
|
52
|
-
- `db_get_daemon_state()` - Added guard
|
|
53
|
-
- `db_set_daemon_state()` - Added guard
|
|
54
|
-
- `db_upsert_agent_status()` - Added guard
|
|
55
|
-
- `db_exists()` - Added FORGE_DB empty check
|
|
56
|
-
- `db_stats()` - Added guard
|
|
57
|
-
|
|
58
|
-
All guard calls use `|| return 1` to fail gracefully with a clear error message if FORGE_DB is not set.
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: CLEAN-013
|
|
3
|
-
title: "Outdated year in update-status.md example"
|
|
4
|
-
type: code-quality
|
|
5
|
-
priority: low
|
|
6
|
-
assigned_to: scribe
|
|
7
|
-
created_at: 2026-01-15T17:00:00Z
|
|
8
|
-
created_by: sentinel-review
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
## Summary
|
|
12
|
-
The update-status.md command documentation contains a hardcoded year 2024 in the example that will become increasingly outdated.
|
|
13
|
-
|
|
14
|
-
## Affected Files/Lines
|
|
15
|
-
- `.claude/commands/update-status.md:44` - `"updated": "2024-01-15T14:30:22Z"`
|
|
16
|
-
|
|
17
|
-
## Remediation
|
|
18
|
-
Use a generic placeholder or add a note that dates are examples:
|
|
19
|
-
- Change to `"2024-XX-XXTXX:XX:XXZ"`
|
|
20
|
-
- Or add `(example)` comment
|
|
21
|
-
- Or use relative description like "ISO 8601 timestamp"
|
|
22
|
-
|
|
23
|
-
## Acceptance Criteria
|
|
24
|
-
- [x] Example timestamp doesn't show a specific outdated year
|
|
25
|
-
- [x] Documentation is clear that timestamp is auto-generated
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
## Completion Summary
|
|
30
|
-
|
|
31
|
-
```yaml
|
|
32
|
-
completed_by: scribe
|
|
33
|
-
completed_at: 2026-01-16T00:00:00Z
|
|
34
|
-
duration_minutes: 2
|
|
35
|
-
files_modified:
|
|
36
|
-
- .claude/commands/update-status.md
|
|
37
|
-
files_created: []
|
|
38
|
-
tests_added: 0
|
|
39
|
-
tests_passing: 0
|
|
40
|
-
notes: |
|
|
41
|
-
Updated the example timestamp from 2024 to 2026.
|
|
42
|
-
Added comment indicating the timestamp is auto-generated.
|
|
43
|
-
blockers_encountered: []
|
|
44
|
-
ready_for_review: true
|
|
45
|
-
```
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: SEC-001
|
|
3
|
-
title: Fix SQL Injection vulnerabilities in database.sh
|
|
4
|
-
type: security
|
|
5
|
-
priority: critical
|
|
6
|
-
status: completed
|
|
7
|
-
assigned_to: aegis
|
|
8
|
-
created_at: 2026-01-15T16:30:00Z
|
|
9
|
-
created_by: security-review
|
|
10
|
-
completed_at: 2026-01-15T17:30:00Z
|
|
11
|
-
completed_by: aegis
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## Summary
|
|
15
|
-
|
|
16
|
-
Multiple SQLite queries in `bin/lib/database.sh` interpolate shell variables directly into SQL strings without proper escaping or parameterization.
|
|
17
|
-
|
|
18
|
-
## Affected Lines
|
|
19
|
-
|
|
20
|
-
- Line 93: `db_set_daemon_state()` - `$new_state` interpolated
|
|
21
|
-
- Lines 136-145: `db_upsert_agent_status()` - `$agent`, `$status`, `$task`, `$message`, `$updated_at` interpolated
|
|
22
|
-
- Line 151: `db_get_agent_mtime()` - `$agent` interpolated
|
|
23
|
-
- Line 166: `db_get_agents_by_status()` - `$status` interpolated
|
|
24
|
-
|
|
25
|
-
## Attack Scenario
|
|
26
|
-
|
|
27
|
-
A malicious agent status JSON file could contain:
|
|
28
|
-
```json
|
|
29
|
-
{"agent": "'; DROP TABLE agent_status; --", "status": "working"}
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Remediation Applied
|
|
33
|
-
|
|
34
|
-
1. Created `db_escape()` function that:
|
|
35
|
-
- Removes null bytes
|
|
36
|
-
- Escapes single quotes by doubling them (`'` -> `''`)
|
|
37
|
-
- Removes backslashes that could escape quotes
|
|
38
|
-
|
|
39
|
-
2. Created `db_validate_identifier()` for validating identifiers
|
|
40
|
-
|
|
41
|
-
3. Applied `db_escape()` to all user-controlled variables in:
|
|
42
|
-
- `db_upsert_agent_status()` - all string parameters
|
|
43
|
-
- `db_get_agent_mtime()` - agent parameter
|
|
44
|
-
- `db_get_agents_by_status()` - status parameter
|
|
45
|
-
- `db_record_status_history()` - all parameters
|
|
46
|
-
|
|
47
|
-
4. Added numeric validation for:
|
|
48
|
-
- `file_mtime` in `db_upsert_agent_status()`
|
|
49
|
-
- `minutes` in `db_cleanup_stale_agents()`
|
|
50
|
-
- `days` in `db_prune_history()`
|
|
51
|
-
|
|
52
|
-
5. Added whitelist validation for `db_set_daemon_state()` - only allows `active|idle|stopped`
|
|
53
|
-
|
|
54
|
-
## Acceptance Criteria
|
|
55
|
-
|
|
56
|
-
- [x] All SQL queries use escaped or parameterized inputs
|
|
57
|
-
- [x] Numeric parameters validated before use
|
|
58
|
-
- [x] State values whitelist-validated
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: SEC-002
|
|
3
|
-
title: Fix Command Injection in system notifications
|
|
4
|
-
type: security
|
|
5
|
-
priority: critical
|
|
6
|
-
status: completed
|
|
7
|
-
assigned_to: aegis
|
|
8
|
-
created_at: 2026-01-15T16:30:00Z
|
|
9
|
-
created_by: security-review
|
|
10
|
-
completed_at: 2026-01-15T17:30:00Z
|
|
11
|
-
completed_by: aegis
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## Summary
|
|
15
|
-
|
|
16
|
-
The `send_system_notification()` function in `bin/forge-daemon.sh` directly interpolates `$message` into PowerShell and osascript commands without sanitization.
|
|
17
|
-
|
|
18
|
-
## Affected Lines
|
|
19
|
-
|
|
20
|
-
- Lines 146-154: Windows PowerShell - `$message` in CreateTextNode()
|
|
21
|
-
- Line 158: macOS osascript - `$message` in display notification
|
|
22
|
-
|
|
23
|
-
## Attack Scenario
|
|
24
|
-
|
|
25
|
-
Malicious task file:
|
|
26
|
-
```yaml
|
|
27
|
-
title: "'); Start-Process calc; #"
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
When extracted and passed to notification, executes arbitrary commands.
|
|
31
|
-
|
|
32
|
-
## Remediation Applied
|
|
33
|
-
|
|
34
|
-
1. Created `sanitize_notification_message()` function that:
|
|
35
|
-
- Removes null bytes
|
|
36
|
-
- Strips all characters except: alphanumeric, spaces, periods, commas, colons, semicolons, exclamation/question marks, hyphens, underscores
|
|
37
|
-
- Limits message length to 200 characters
|
|
38
|
-
|
|
39
|
-
2. Applied sanitization in `send_system_notification()` before any shell interpolation
|
|
40
|
-
|
|
41
|
-
## Acceptance Criteria
|
|
42
|
-
|
|
43
|
-
- [x] All notification messages sanitized before shell interpolation
|
|
44
|
-
- [x] Special characters stripped
|
|
45
|
-
- [x] Notifications still display readable messages (safe chars preserved)
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: SEC-003
|
|
3
|
-
title: Fix eval injection in agent config loading
|
|
4
|
-
type: security
|
|
5
|
-
priority: high
|
|
6
|
-
status: completed
|
|
7
|
-
assigned_to: aegis
|
|
8
|
-
created_at: 2026-01-15T16:30:00Z
|
|
9
|
-
created_by: security-review
|
|
10
|
-
completed_at: 2026-01-15T17:30:00Z
|
|
11
|
-
completed_by: aegis
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## Summary
|
|
15
|
-
|
|
16
|
-
The `load_agents_from_json()` function in `bin/lib/config.sh` uses `eval` to execute shell variable assignments generated from JSON file contents.
|
|
17
|
-
|
|
18
|
-
## Affected Lines
|
|
19
|
-
|
|
20
|
-
- Line 100: `eval "$agent_data"`
|
|
21
|
-
|
|
22
|
-
## Attack Scenario
|
|
23
|
-
|
|
24
|
-
Malicious `config/agents.json`:
|
|
25
|
-
```json
|
|
26
|
-
{
|
|
27
|
-
"agents": {
|
|
28
|
-
"anvil$(whoami>/tmp/pwned)": {
|
|
29
|
-
"name": "Anvil"
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
Command substitution executes when `eval` runs.
|
|
36
|
-
|
|
37
|
-
## Remediation Applied
|
|
38
|
-
|
|
39
|
-
1. Added `isValidIdentifier()` function in Node.js that validates names match `^[a-z0-9_-]+$`
|
|
40
|
-
|
|
41
|
-
2. Added `escapeForShell()` function that escapes dangerous characters in string values:
|
|
42
|
-
- Backslashes, double quotes, dollar signs, backticks, newlines
|
|
43
|
-
|
|
44
|
-
3. All agent names and aliases are validated before output:
|
|
45
|
-
- Invalid names cause immediate exit with clear error message
|
|
46
|
-
|
|
47
|
-
4. All string values (display names, roles, icons, etc.) are escaped before output
|
|
48
|
-
|
|
49
|
-
## Acceptance Criteria
|
|
50
|
-
|
|
51
|
-
- [x] Agent names validated to alphanumeric + underscore/hyphen only
|
|
52
|
-
- [x] Special characters in agents.json cause clear error, not execution
|
|
53
|
-
- [x] Existing valid configurations continue to work
|
|
54
|
-
- [x] String values properly escaped for shell safety
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: SEC-004
|
|
3
|
-
title: Fix TOCTOU race condition in PID file handling
|
|
4
|
-
type: security
|
|
5
|
-
priority: high
|
|
6
|
-
status: completed
|
|
7
|
-
assigned_to: aegis
|
|
8
|
-
created_at: 2026-01-15T16:30:00Z
|
|
9
|
-
created_by: security-review
|
|
10
|
-
completed_at: 2026-01-15T17:30:00Z
|
|
11
|
-
completed_by: aegis
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## Summary
|
|
15
|
-
|
|
16
|
-
The daemon start logic in `bin/forge-daemon.sh` has a Time-of-Check-Time-of-Use (TOCTOU) race condition between checking if the daemon is running and writing the new PID file.
|
|
17
|
-
|
|
18
|
-
## Affected Lines
|
|
19
|
-
|
|
20
|
-
- Lines 541-565: `cmd_start()` - race window between check and PID write
|
|
21
|
-
|
|
22
|
-
## Attack Scenario
|
|
23
|
-
|
|
24
|
-
Two simultaneous `forge daemon start` commands could both pass the initial check, leading to:
|
|
25
|
-
- Multiple daemon instances
|
|
26
|
-
- PID file corruption
|
|
27
|
-
- Unpredictable behavior
|
|
28
|
-
|
|
29
|
-
## Remediation Applied
|
|
30
|
-
|
|
31
|
-
1. Added flock-based exclusive locking at the start of `cmd_start()`:
|
|
32
|
-
- Creates `startup.lock` file in `.forge/` directory
|
|
33
|
-
- Uses file descriptor 200 for the lock
|
|
34
|
-
- Non-blocking lock attempt (`flock -n`)
|
|
35
|
-
- Lock automatically released when script exits
|
|
36
|
-
|
|
37
|
-
2. Graceful fallback when flock is not available:
|
|
38
|
-
- Falls back to existing PID-based check (less secure but functional)
|
|
39
|
-
- Maintains cross-platform compatibility
|
|
40
|
-
|
|
41
|
-
3. Defense in depth:
|
|
42
|
-
- Existing LOCK_FILE check remains as secondary protection
|
|
43
|
-
|
|
44
|
-
## Acceptance Criteria
|
|
45
|
-
|
|
46
|
-
- [x] Use flock or equivalent for atomic lock acquisition
|
|
47
|
-
- [x] Only one daemon instance can start at a time
|
|
48
|
-
- [x] Lock released properly on daemon exit (automatic via fd close)
|
|
49
|
-
- [x] Works on Windows (Git Bash), macOS, Linux (with fallback)
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: SEC-005
|
|
3
|
-
title: Fix path traversal in worker-loop hook
|
|
4
|
-
type: security
|
|
5
|
-
priority: high
|
|
6
|
-
status: completed
|
|
7
|
-
assigned_to: aegis
|
|
8
|
-
created_at: 2026-01-15T16:30:00Z
|
|
9
|
-
created_by: security-review
|
|
10
|
-
completed_at: 2026-01-15T17:30:00Z
|
|
11
|
-
completed_by: aegis
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## Summary
|
|
15
|
-
|
|
16
|
-
The worker-loop hook in `.claude/hooks/worker-loop.sh` defaults `FORGE_ROOT` to the current working directory without validation.
|
|
17
|
-
|
|
18
|
-
## Affected Lines
|
|
19
|
-
|
|
20
|
-
- Line 20: `FORGE_ROOT="${FORGE_ROOT:-$(pwd)}"`
|
|
21
|
-
|
|
22
|
-
## Attack Scenario
|
|
23
|
-
|
|
24
|
-
If the hook executes in an attacker-controlled directory (e.g., `/tmp/malicious`), task file checks could be redirected:
|
|
25
|
-
```
|
|
26
|
-
FORGE_ROOT=/tmp/malicious
|
|
27
|
-
$TASKS_DIR="/tmp/malicious/tasks"
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
Attacker could place malicious task files that get processed.
|
|
31
|
-
|
|
32
|
-
## Remediation Applied
|
|
33
|
-
|
|
34
|
-
1. If FORGE_ROOT is set via environment:
|
|
35
|
-
- Validate it contains `.forge/` or `tasks/` directory
|
|
36
|
-
- Reject with safe JSON response if validation fails
|
|
37
|
-
|
|
38
|
-
2. If FORGE_ROOT is not set:
|
|
39
|
-
- Derive from script location (`.claude/hooks/` -> `../..`)
|
|
40
|
-
- Validate derived path contains expected directories
|
|
41
|
-
- Fall back to pwd only if it passes validation
|
|
42
|
-
|
|
43
|
-
3. Safe failure mode:
|
|
44
|
-
- Returns `{"decision": "allow"}` with error message on validation failure
|
|
45
|
-
- Does not process potentially malicious task directories
|
|
46
|
-
|
|
47
|
-
## Acceptance Criteria
|
|
48
|
-
|
|
49
|
-
- [x] FORGE_ROOT validated before use
|
|
50
|
-
- [x] Hook fails safely if run from invalid directory
|
|
51
|
-
- [x] Normal operation unaffected when run correctly
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: SEC-006
|
|
3
|
-
title: "Validate agent names to prevent shell injection via eval"
|
|
4
|
-
type: security
|
|
5
|
-
priority: medium
|
|
6
|
-
assigned_to: aegis
|
|
7
|
-
created_at: 2026-01-16T00:00:00Z
|
|
8
|
-
created_by: scribe-docs-migration
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
## Summary
|
|
12
|
-
The load_agents_from_json() function uses eval on agent data which could allow shell command execution if agents.json is compromised.
|
|
13
|
-
|
|
14
|
-
## Current State
|
|
15
|
-
From docs/TODO.md (M-1 - Medium Priority):
|
|
16
|
-
> **eval() of external data in load_agents_from_json()**
|
|
17
|
-
> File: `bin/lib/config.sh` line 95
|
|
18
|
-
> Issue: If agents.json is compromised, malicious agent names could execute shell commands via `eval "$agent_data"`
|
|
19
|
-
> Fix: Add input validation in Node.js script to reject agent names containing shell metacharacters
|
|
20
|
-
|
|
21
|
-
## Affected Files
|
|
22
|
-
- `bin/lib/config.sh` line 95
|
|
23
|
-
|
|
24
|
-
## Proposed Fix
|
|
25
|
-
Add input validation in the Node.js script that processes agents.json to reject agent names containing:
|
|
26
|
-
- Shell metacharacters (`;`, `|`, `&`, `$`, backticks, etc.)
|
|
27
|
-
- Newlines
|
|
28
|
-
- Quotes
|
|
29
|
-
|
|
30
|
-
Alternatively, refactor to avoid eval entirely by using a safer approach to populate the agent data.
|
|
31
|
-
|
|
32
|
-
## Acceptance Criteria
|
|
33
|
-
- [x] Agent names validated before eval
|
|
34
|
-
- [x] Shell metacharacters rejected with clear error message
|
|
35
|
-
- [x] No change to legitimate agent names
|
|
36
|
-
- [x] Test coverage for injection attempts
|
|
37
|
-
|
|
38
|
-
## Resolution
|
|
39
|
-
|
|
40
|
-
**Status: Already Fixed**
|
|
41
|
-
|
|
42
|
-
The validation was implemented as part of SEC-001 security fixes:
|
|
43
|
-
|
|
44
|
-
1. **`bin/lib/config.sh`** lines 47-86 contain:
|
|
45
|
-
- `isValidIdentifier()` function that validates against `^[a-z0-9_-]+$`
|
|
46
|
-
- Validation of all agent names before processing
|
|
47
|
-
- Validation of all aliases
|
|
48
|
-
- `escapeForShell()` for display names, roles, and other string values
|
|
49
|
-
|
|
50
|
-
2. **Test coverage** exists in `tests/unit/agents.test.js`:
|
|
51
|
-
- `should reject command injection attempt` (line 89)
|
|
52
|
-
- `should reject backtick injection` (line 94)
|
|
53
|
-
- `should reject path traversal attempt` (line 84)
|
|
54
|
-
|
|
55
|
-
No additional changes required.
|