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.
- package/bin/batch-runner.mjs +31 -2
- package/bin/engine/admission.mjs +294 -0
- package/bin/engine/admission.test.mjs +265 -0
- package/bin/engine/invariants.mjs +17 -4
- package/bin/engine/phases.mjs +201 -35
- package/bin/engine/resolve.mjs +256 -0
- package/bin/engine/resolve.test.mjs +149 -0
- package/bin/engine/runlog.mjs +11 -1
- package/bin/engine/state.mjs +20 -28
- package/bin/engine-cli.mjs +86 -5
- package/bin/engine.mjs +543 -36
- package/bin/forgedock.mjs +397 -59
- package/bin/hooks/interactive-engine.mjs +50 -24
- package/bin/hooks/pre-tool-use.mjs +191 -13
- package/bin/journey.mjs +586 -44
- package/bin/labels.json +5 -0
- package/bin/runner.mjs +478 -10
- package/bin/watch-utils.mjs +258 -0
- package/commands/cleanup.md +34 -5
- package/commands/issue.md +14 -4
- package/commands/orchestrate/config.md +43 -1
- package/commands/orchestrate/phase-1-resolve.md +348 -11
- package/commands/orchestrate/phase-3-dependency.md +272 -49
- package/commands/orchestrate/phase-4-execution.md +622 -60
- package/commands/orchestrate/phase-5-cleanup.md +2 -0
- package/commands/quality-gate.md +6 -6
- package/commands/review-pr-staging.md +51 -8
- package/commands/review-pr.md +120 -39
- package/commands/upgrade-deps.md +7 -2
- package/commands/work-on/decompose.md +2 -0
- package/commands/work-on/investigate.md +22 -4
- package/commands/work-on/remediate.md +55 -4
- package/commands/work-on/review.md +40 -1
- package/commands/work-on.md +19 -4
- package/docs/CONFIG.md +120 -0
- package/docs/spec/eval-run-result.md +8 -4
- package/docs/spec/label-state-machine.md +9 -0
- package/package.json +2 -2
- package/packages/protocol/src/emit.js +5 -22
- package/packages/protocol/src/html-comment-escape.js +68 -0
- package/packages/protocol/src/index.js +1 -0
- package/packages/protocol/src/parse.js +5 -6
- package/packages/protocol/src/phases.js +105 -0
- package/packages/protocol/src/types.js +17 -0
- package/packages/protocol/src/validate.js +24 -1
- package/scripts/check-admission-parity.mjs +167 -0
- package/scripts/check-command-side-effects.sh +181 -66
- package/scripts/check-phase-registry-drift.mjs +118 -0
- package/scripts/check-spec-markers.sh +3 -0
- package/scripts/classify-lane.sh +29 -3
- package/scripts/derive-finding-milestone.sh +184 -0
- package/scripts/doctor-pipeline-state.sh +1 -0
- package/scripts/extract-affected-files.sh +232 -0
- package/scripts/extract-affected-files.test.sh +331 -0
- package/scripts/forge-run.sh +39 -4
- package/scripts/issue-dedup.sh +69 -8
- package/scripts/issue-dedup.test.sh +142 -0
- 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
|