forgedock 1.3.0 → 1.5.0

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.
Files changed (58) hide show
  1. package/bin/batch-runner.mjs +31 -2
  2. package/bin/engine/admission.mjs +294 -0
  3. package/bin/engine/admission.test.mjs +265 -0
  4. package/bin/engine/invariants.mjs +17 -4
  5. package/bin/engine/phases.mjs +201 -35
  6. package/bin/engine/resolve.mjs +256 -0
  7. package/bin/engine/resolve.test.mjs +149 -0
  8. package/bin/engine/runlog.mjs +11 -1
  9. package/bin/engine/state.mjs +20 -28
  10. package/bin/engine-cli.mjs +86 -5
  11. package/bin/engine.mjs +543 -36
  12. package/bin/forgedock.mjs +397 -59
  13. package/bin/hooks/interactive-engine.mjs +50 -24
  14. package/bin/hooks/pre-tool-use.mjs +191 -13
  15. package/bin/journey.mjs +586 -44
  16. package/bin/labels.json +5 -0
  17. package/bin/runner.mjs +478 -10
  18. package/bin/watch-utils.mjs +258 -0
  19. package/commands/cleanup.md +34 -5
  20. package/commands/issue.md +14 -4
  21. package/commands/orchestrate/config.md +43 -1
  22. package/commands/orchestrate/phase-1-resolve.md +348 -11
  23. package/commands/orchestrate/phase-3-dependency.md +272 -49
  24. package/commands/orchestrate/phase-4-execution.md +622 -60
  25. package/commands/orchestrate/phase-5-cleanup.md +2 -0
  26. package/commands/quality-gate.md +6 -6
  27. package/commands/review-pr-staging.md +51 -8
  28. package/commands/review-pr.md +120 -39
  29. package/commands/upgrade-deps.md +7 -2
  30. package/commands/work-on/decompose.md +2 -0
  31. package/commands/work-on/investigate.md +22 -4
  32. package/commands/work-on/remediate.md +55 -4
  33. package/commands/work-on/review.md +40 -1
  34. package/commands/work-on.md +19 -4
  35. package/docs/CONFIG.md +120 -0
  36. package/docs/spec/eval-run-result.md +8 -4
  37. package/docs/spec/label-state-machine.md +9 -0
  38. package/package.json +2 -2
  39. package/packages/protocol/src/emit.js +5 -22
  40. package/packages/protocol/src/html-comment-escape.js +68 -0
  41. package/packages/protocol/src/index.js +1 -0
  42. package/packages/protocol/src/parse.js +5 -6
  43. package/packages/protocol/src/phases.js +105 -0
  44. package/packages/protocol/src/types.js +17 -0
  45. package/packages/protocol/src/validate.js +24 -1
  46. package/scripts/check-admission-parity.mjs +167 -0
  47. package/scripts/check-command-side-effects.sh +181 -66
  48. package/scripts/check-phase-registry-drift.mjs +118 -0
  49. package/scripts/check-spec-markers.sh +3 -0
  50. package/scripts/classify-lane.sh +29 -3
  51. package/scripts/derive-finding-milestone.sh +184 -0
  52. package/scripts/doctor-pipeline-state.sh +1 -0
  53. package/scripts/extract-affected-files.sh +232 -0
  54. package/scripts/extract-affected-files.test.sh +331 -0
  55. package/scripts/forge-run.sh +39 -4
  56. package/scripts/issue-dedup.sh +69 -8
  57. package/scripts/issue-dedup.test.sh +142 -0
  58. package/scripts/severity-to-priority.sh +81 -0
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env bash
2
+ # issue-dedup.test.sh — Unit-style tests for scripts/issue-dedup.sh's --exclude flag
3
+ #
4
+ # No network/GitHub API access required: `gh` is replaced with a mock that
5
+ # returns fixture candidate lists via the MOCK_GH_CANDIDATES env var, mimicking
6
+ # the "\(.number)\t\(.title)" projection issue-dedup.sh expects from
7
+ # `gh issue list --json number,title --jq '...'`.
8
+ #
9
+ # Usage: bash scripts/issue-dedup.test.sh
10
+ # Exit code: 0 if all assertions pass, 1 if any fail.
11
+ #
12
+ # SPDX-FileCopyrightText: Copyright (c) RapierCraft Studios
13
+ # SPDX-License-Identifier: AGPL-3.0-or-later
14
+
15
+ set -uo pipefail
16
+
17
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
18
+ DEDUP="$SCRIPT_DIR/issue-dedup.sh"
19
+
20
+ TMP_BIN=$(mktemp -d)
21
+ TMP_FIXTURES=$(mktemp -d)
22
+ cleanup() {
23
+ rm -rf "$TMP_BIN" "$TMP_FIXTURES"
24
+ }
25
+ trap cleanup EXIT
26
+
27
+ # --------------------------------------------------------------------------- #
28
+ # Mock `gh` — intercepts `gh issue list ...` and prints the fixture file named
29
+ # by $MOCK_GH_CANDIDATES (tab-separated "number\ttitle" lines), ignoring all
30
+ # other flags/subcommands issue-dedup.sh passes through. Any other `gh`
31
+ # invocation is treated as an unexpected test setup error.
32
+ # --------------------------------------------------------------------------- #
33
+ cat > "$TMP_BIN/gh" <<'MOCK'
34
+ #!/usr/bin/env bash
35
+ if [[ "$1" == "issue" && "$2" == "list" ]]; then
36
+ if [[ -n "${MOCK_GH_CANDIDATES:-}" && -f "${MOCK_GH_CANDIDATES:-}" ]]; then
37
+ cat "$MOCK_GH_CANDIDATES"
38
+ fi
39
+ exit 0
40
+ fi
41
+ echo "issue-dedup.test.sh: unexpected gh mock invocation: $*" >&2
42
+ exit 1
43
+ MOCK
44
+ chmod +x "$TMP_BIN/gh"
45
+
46
+ export PATH="$TMP_BIN:$PATH"
47
+
48
+ PASS=0
49
+ FAIL=0
50
+
51
+ # assert_exit <description> <expected_exit> <dedup args...>
52
+ assert_exit() {
53
+ local desc="$1" expected="$2"
54
+ shift 2
55
+ set +e
56
+ OUT=$("$DEDUP" "$@" 2>&1)
57
+ ACTUAL=$?
58
+ set -e
59
+ if [[ "$ACTUAL" -eq "$expected" ]]; then
60
+ echo "PASS: $desc"
61
+ PASS=$((PASS + 1))
62
+ else
63
+ echo "FAIL: $desc (expected exit $expected, got $ACTUAL)"
64
+ echo " output: $OUT"
65
+ FAIL=$((FAIL + 1))
66
+ fi
67
+ }
68
+
69
+ PROPOSED_TITLE="fix(batch): duplicate detection review findings"
70
+
71
+ # --------------------------------------------------------------------------- #
72
+ # Scenario A: candidate set contains ONLY the batch's own declared members.
73
+ # Both titles are engineered to share >=3 normalized tokens (length >= 4) with
74
+ # the proposed title: "duplicate", "detection", "review"/"findings".
75
+ # --------------------------------------------------------------------------- #
76
+ MEMBERS_ONLY="$TMP_FIXTURES/members_only.tsv"
77
+ cat > "$MEMBERS_ONLY" <<'EOF'
78
+ 2422 fix: duplicate detection review token overlap
79
+ 2424 fix: duplicate detection findings batching logic
80
+ EOF
81
+
82
+ MOCK_GH_CANDIDATES="$MEMBERS_ONLY" assert_exit \
83
+ "baseline (no --exclude): batch title collides with its own members -> exit 1" \
84
+ 1 "$PROPOSED_TITLE" -R test/repo
85
+
86
+ MOCK_GH_CANDIDATES="$MEMBERS_ONLY" assert_exit \
87
+ "--exclude '2422,2424': batch title excludes its own members -> exit 0" \
88
+ 0 "$PROPOSED_TITLE" -R test/repo --exclude "2422,2424"
89
+
90
+ MOCK_GH_CANDIDATES="$MEMBERS_ONLY" assert_exit \
91
+ "--exclude=2422,2424 (pre-joined form) -> exit 0" \
92
+ 0 "$PROPOSED_TITLE" -R test/repo --exclude=2422,2424
93
+
94
+ # --------------------------------------------------------------------------- #
95
+ # Scenario B: candidate set has the declared members PLUS an unrelated
96
+ # non-member issue (#2600) that also collides on token overlap. Excluding the
97
+ # members must NOT suppress the non-member match — protection is preserved.
98
+ # --------------------------------------------------------------------------- #
99
+ MEMBERS_PLUS_NONMEMBER="$TMP_FIXTURES/members_plus_nonmember.tsv"
100
+ cat > "$MEMBERS_PLUS_NONMEMBER" <<'EOF'
101
+ 2422 fix: duplicate detection review token overlap
102
+ 2424 fix: duplicate detection findings batching logic
103
+ 2600 fix: duplicate detection review triage
104
+ EOF
105
+
106
+ MOCK_GH_CANDIDATES="$MEMBERS_PLUS_NONMEMBER" assert_exit \
107
+ "--exclude '2422,2424' with a real non-member duplicate present -> still exit 1" \
108
+ 1 "$PROPOSED_TITLE" -R test/repo --exclude "2422,2424"
109
+
110
+ # --------------------------------------------------------------------------- #
111
+ # Scenario C: exclusion list has no bearing when there is no candidate overlap
112
+ # at all — sanity check that --exclude doesn't accidentally suppress dedup.
113
+ # --------------------------------------------------------------------------- #
114
+ NO_OVERLAP="$TMP_FIXTURES/no_overlap.tsv"
115
+ cat > "$NO_OVERLAP" <<'EOF'
116
+ 9001 feat: totally unrelated subsystem work
117
+ EOF
118
+
119
+ MOCK_GH_CANDIDATES="$NO_OVERLAP" assert_exit \
120
+ "no overlap at all, --exclude present but irrelevant -> exit 0" \
121
+ 0 "$PROPOSED_TITLE" -R test/repo --exclude "2422,2424"
122
+
123
+ # --------------------------------------------------------------------------- #
124
+ # Scenario D: malformed / non-numeric exclusion tokens are silently dropped,
125
+ # not a usage error.
126
+ # --------------------------------------------------------------------------- #
127
+ MOCK_GH_CANDIDATES="$MEMBERS_ONLY" assert_exit \
128
+ "malformed --exclude tokens (non-numeric) are dropped, real numeric ones still apply -> exit 0" \
129
+ 0 "$PROPOSED_TITLE" -R test/repo --exclude "2422, 2424, abc, "
130
+
131
+ # --------------------------------------------------------------------------- #
132
+ # Scenario E: --exclude combined with existing -R parsing (two-token and
133
+ # pre-joined forms) does not regress prior -R argument-parsing fixes (#1530,
134
+ # #1625).
135
+ # --------------------------------------------------------------------------- #
136
+ MOCK_GH_CANDIDATES="$MEMBERS_ONLY" assert_exit \
137
+ "--exclude alongside pre-joined -R token -> exit 0" \
138
+ 0 "$PROPOSED_TITLE" "-R test/repo" --exclude "2422,2424"
139
+
140
+ echo ""
141
+ echo "Results: $PASS passed, $FAIL failed"
142
+ [[ "$FAIL" -eq 0 ]]
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env bash
2
+ # SPDX-FileCopyrightText: Copyright (c) RapierCraft Studios
3
+ # SPDX-License-Identifier: AGPL-3.0-or-later
4
+ #
5
+ # severity-to-priority.sh — Single source of truth for the Severity → priority:*
6
+ # label mapping used by review-finding issue creation.
7
+ #
8
+ # Usage:
9
+ # severity-to-priority.sh <SEVERITY>
10
+ #
11
+ # SEVERITY One of: CRITICAL, HIGH, MEDIUM, LOW (case-sensitive,
12
+ # matches the exact tokens written into a finding's
13
+ # `**Severity**:` body field by commands/review-pr-agents/*.md)
14
+ #
15
+ # Mapping (fixed — do not add a second copy of this table anywhere else;
16
+ # both commands/review-pr.md and commands/review-pr-staging.md call this
17
+ # script rather than hand-rolling their own copy, specifically so the two
18
+ # specs cannot independently drift the way they did before this fix):
19
+ #
20
+ # CRITICAL -> priority:P0
21
+ # HIGH -> priority:P1
22
+ # MEDIUM -> priority:P2
23
+ # LOW -> priority:P3
24
+ #
25
+ # NOTE: an `INFO -> priority:P3` branch previously existed here (forge#2447)
26
+ # but was removed (forge#2480) — no `commands/review-pr-agents/*.md` persona
27
+ # ever documented or instructed emitting `INFO` as a `**Severity**` value, and
28
+ # neither finding-body template (`review-pr.md`/`review-pr-staging.md`) ever
29
+ # listed it as valid, making the branch permanently unreachable dead code. If
30
+ # a real producer for `INFO` is added in the future, reintroduce the mapping
31
+ # here AND update both finding-body template enums AND the relevant
32
+ # review-pr-agents persona(s) in the same change — see forge#2480.
33
+ #
34
+ # IMPORTANT: this maps SEVERITY, never Confidence (CONFIRMED/LIKELY/POSSIBLE).
35
+ # Confidence and Severity are independent axes of a finding — conflating them
36
+ # is exactly the bug this script exists to prevent (forge#2447: a LOW-severity,
37
+ # CONFIRMED-confidence finding was previously labeled priority:P1 because the
38
+ # label was derived from Confidence instead of Severity, defeating the
39
+ # orchestrator's P3 batching rule for LOW-severity nits).
40
+ #
41
+ # Output: the resolved `priority:P*` label on stdout, nothing else.
42
+ #
43
+ # Exit codes:
44
+ # 0 success — label printed to stdout
45
+ # 1 error (missing argument or unrecognized severity — fails loud rather
46
+ # than silently guessing a default priority)
47
+ #
48
+ # Example:
49
+ # FINDING_PRIORITY=$(scripts/severity-to-priority.sh "$FINDING_SEVERITY")
50
+ #
51
+ # <!-- Added: forge#2447 -->
52
+
53
+ set -euo pipefail
54
+
55
+ if [ "$#" -lt 1 ]; then
56
+ echo "ERROR: Usage: severity-to-priority.sh <SEVERITY>" >&2
57
+ echo " SEVERITY: CRITICAL | HIGH | MEDIUM | LOW" >&2
58
+ exit 1
59
+ fi
60
+
61
+ SEVERITY="$1"
62
+
63
+ case "$SEVERITY" in
64
+ CRITICAL)
65
+ echo "priority:P0"
66
+ ;;
67
+ HIGH)
68
+ echo "priority:P1"
69
+ ;;
70
+ MEDIUM)
71
+ echo "priority:P2"
72
+ ;;
73
+ LOW)
74
+ echo "priority:P3"
75
+ ;;
76
+ *)
77
+ echo "ERROR: Unrecognized severity: '$SEVERITY'" >&2
78
+ echo " Valid severities: CRITICAL, HIGH, MEDIUM, LOW" >&2
79
+ exit 1
80
+ ;;
81
+ esac