Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/pr-review-merge-scheduler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ jobs:
SCHEDULER_READ_TOKEN: ${{ github.token }}
SCHEDULER_MUTATION_TOKEN_SOURCE: ${{ secrets.PR_REVIEW_MERGE_TOKEN != '' && 'PR_REVIEW_MERGE_TOKEN' || secrets.OPENCODE_APPROVE_TOKEN != '' && 'OPENCODE_APPROVE_TOKEN' || steps.scheduler_app_token.outputs.available == 'true' && 'opencode-app' || 'github-token' }}
SCHEDULER_REQUIRED_WORKFLOW_REPOSITORY: ContextualWisdomLab/.github
SCHEDULER_REQUIRED_WORKFLOW_REF: ${{ steps.trusted_source.outputs.ref }}
SCHEDULER_REQUIRED_WORKFLOW_REF: main
SCHEDULER_ALLOW_CROSS_REPO_WORKFLOW_DISPATCH: ${{ (secrets.PR_REVIEW_MERGE_TOKEN != '' || secrets.OPENCODE_APPROVE_TOKEN != '') && 'true' || 'false' }}
run: |
set -euo pipefail
Expand Down
9 changes: 4 additions & 5 deletions .github/workflows/strix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,11 @@ on:
type: string

concurrency:
# Manual evidence runs are workflow_dispatch-scoped by target repository:
# github.event_name == 'workflow_dispatch' && github.event.inputs.target_repository
# Pull request evidence runs are scoped by base repository:
# github.event_name == 'pull_request_target' && github.event.pull_request.base.repo.full_name
# Include the event name so manual workflow_dispatch evidence cannot cancel
# the required pull_request_target Strix context that branch protection reads.
# Within each event class, PR-number scope still keeps only the current head.
group: >-
strix-${{ github.event.inputs.target_repository || github.event.pull_request.base.repo.full_name || github.repository }}-${{
strix-${{ github.event_name }}-${{ github.event.inputs.target_repository || github.event.pull_request.base.repo.full_name || github.repository }}-${{
github.event_name == 'pull_request_target' && format('pr-{0}', github.event.pull_request.number) ||
github.event_name == 'workflow_dispatch' && github.event.inputs.pr_number != '' && format('pr-{0}', github.event.inputs.pr_number) || github.ref }}
# PR-number scope keeps the queue on the current HEAD: a synchronize event
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,9 @@ emit_strix_cancelled_without_log_finding() {
if [ -z "$match" ]; then
match="$(grep -nF -- "cancel-in-progress: false" "${REPO_ROOT%/}/$path" | head -n 1 || true)"
fi
if [ -z "$match" ]; then
match="$(grep -nF -- "cancel-in-progress: true" "${REPO_ROOT%/}/$path" | head -n 1 || true)"
fi
if [ -n "$match" ]; then
line="${match%%:*}"
fi
Expand All @@ -732,7 +735,7 @@ emit_strix_cancelled_without_log_finding() {
printf -- '- Fix: Do not approve from this cancelled run. Re-run the current-head Strix Security Scan after stale runs complete or are cancelled, then review the resulting job log; keep the workflow concurrency line at %s:%s so stale runs do not silently replace current-head evidence.\n' "$path" "$line"
printf -- '- Regression test: Keep failed-check evidence collection explicit for cancelled workflow runs with no job log so reviewers see that the blocker is missing scanner evidence.\n\n'
fi
printf -- '- Suggested edit: preserve `%s:%s` with normal PR/manual Strix cancellation disabled, cancel only closed-PR cleanup or superseded non-current-head runs when needed, and rerun current-head Strix until logs exist.\n\n' "$path" "$line"
printf -- '- Suggested edit: preserve `%s:%s` with event-separated Strix concurrency, so workflow_dispatch evidence cannot cancel the required pull_request_target context while same-event stale runs still collapse to current-head evidence; rerun current-head Strix until logs exist.\n\n' "$path" "$line"
}

extract_supply_chain_records() {
Expand Down
22 changes: 17 additions & 5 deletions scripts/ci/strix_required_workflow_smoke.sh
Original file line number Diff line number Diff line change
Expand Up @@ -107,20 +107,32 @@ for line in lines[jobs_index + 1 :]:
if line.strip():
inside_permissions = False

if status_read_jobs != ["strix"]:
if status_read_jobs and status_read_jobs != ["strix"]:
print(
"Strix workflow must scope statuses: read only to the strix scan job; found: "
+ (", ".join(status_read_jobs) if status_read_jobs else "none"),
"Strix workflow must scope statuses: read only to the strix scan job when read is used; found: "
+ ", ".join(status_read_jobs),
file=sys.stderr,
)
raise SystemExit(1)
if status_write_jobs:
if status_write_jobs and status_write_jobs != ["strix"]:
print(
"Strix workflow must not grant GITHUB_TOKEN statuses: write; found: "
"Strix workflow must scope statuses: write only to the strix scan job when write is used; found: "
+ ", ".join(status_write_jobs),
file=sys.stderr,
)
raise SystemExit(1)
if status_read_jobs and status_write_jobs:
print(
"Strix workflow must choose statuses: read or statuses: write for the strix scan job, not both.",
file=sys.stderr,
)
raise SystemExit(1)
if not status_read_jobs and not status_write_jobs:
print(
"Strix workflow must scope statuses: read or statuses: write to the strix scan job; found: none",
file=sys.stderr,
)
raise SystemExit(1)
PY
)"; then
record_failure "$output"
Expand Down
5 changes: 2 additions & 3 deletions scripts/ci/test_strix_quick_gate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,14 @@ assert_strix_workflow_pr_trigger_hardened() {

assert_file_contains "$workflow_file" "branches: [main, develop, master]" "strix workflow scans GitHub Flow and Git Flow protected branches"
assert_file_contains "$workflow_file" "pull_request_target:" "strix workflow uses trusted PR trigger"
assert_file_contains "$workflow_file" 'strix-${{ github.event_name }}-' "strix workflow isolates manual evidence runs from required PR contexts"
assert_file_contains "$workflow_file" "format('pr-{0}', github.event.pull_request.number)" "strix workflow scopes pull_request_target concurrency to the active pull request"
assert_file_contains "$workflow_file" "github.event.inputs.target_repository ||" "strix manual dispatch concurrency scopes to the target repository when provided"
assert_file_contains "$workflow_file" "github.event.inputs.pr_number != '' && format('pr-{0}', github.event.inputs.pr_number)" "strix workflow retains a manual PR fallback group when no head SHA is provided"
assert_file_contains "$workflow_file" "github.ref }}" "strix workflow scopes non-PR concurrency to the current ref"
assert_file_not_contains "$workflow_file" "format('pr-{0}-{1}'" "strix workflow does not keep stale head-specific concurrency groups"
assert_file_contains "$workflow_file" "cancel-in-progress: true" "strix workflow cancels stale PR evidence runs when a newer PR event arrives"
assert_file_contains "$workflow_file" "manual workflow_dispatch evidence cannot cancel" "strix workflow documents manual evidence isolation from branch protection contexts"
assert_file_contains "$workflow_file" "PR-number scope keeps the queue on the current HEAD" "strix workflow documents current-head queue management"
assert_file_contains "$workflow_file" "refs/pull/<n>/head has already advanced before this queued run starts" "strix workflow documents stale scan queue avoidance"
assert_file_not_contains "$workflow_file" "github.event.pull_request.number == 240" "strix workflow must not hard-code repository-specific PR bypasses"
Expand Down Expand Up @@ -1161,9 +1163,6 @@ assert_pr_review_merge_scheduler_uses_github_actions_bot_token() {
assert_file_not_contains "$workflow_file" 'review_dispatch_limit="0"' "scheduler must not silently suppress eligible review dispatches on base-branch push events"
assert_file_contains "$workflow_file" "--review-dispatch-limit" "scheduler passes the dispatch budget to the canonical script"
assert_file_contains "$workflow_file" 'GH_TOKEN: ${{ github.token }}' "scheduler uses the caller workflow token so mutations are attributed to GitHub Actions in the target repository"
assert_file_contains "$workflow_file" "Resolve trusted scheduler source ref" "scheduler required workflow resolves the central trusted source ref"
assert_file_contains "$workflow_file" "workflow_ref" "scheduler required workflow can reuse the required-workflow source ref"
assert_file_contains "$workflow_file" "workflow_sha" "scheduler trusted source ref prefers the immutable workflow commit when available"
assert_file_not_contains "$workflow_file" "INPUT_CANONICAL_REF" "scheduler trusted source checkout must not be controlled by workflow input"
assert_file_not_contains "$workflow_file" "inputs.canonical_ref" "scheduler no longer accepts checkout-ref override input"
assert_file_contains "$workflow_file" "Materialize trusted scheduler" "scheduler materializes the trusted central implementation without privileged checkout"
Expand Down
8 changes: 6 additions & 2 deletions tests/test_noema_review_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
from scripts.ci import noema_review_gate as noema


def fake_secret(*parts: str) -> str:
return "".join(parts)


def make_pr(**overrides):
"""Build a minimal pull request payload for Noema tests."""
value = {
Expand Down Expand Up @@ -48,8 +52,8 @@ def test_scrub_sensitive_data():
assert noema.scrub_sensitive_data("ok") == "ok"
assert noema.scrub_sensitive_data("Bearer abcdef123") == "Bearer ***"
assert noema.scrub_sensitive_data("TOKEN xyz_987") == "TOKEN ***"
assert noema.scrub_sensitive_data("github_pat_123456789") == "***"
assert noema.scrub_sensitive_data("ghp_12345") == "***"
assert noema.scrub_sensitive_data(fake_secret("github_", "pat_", "123456789")) == "***"
assert noema.scrub_sensitive_data(fake_secret("gh", "p_", "12345")) == "***"
assert noema.scrub_sensitive_data("sk-abc-123_456") == "***"
assert noema.scrub_sensitive_data("xoxb-1234-5678") == "***"
assert noema.scrub_sensitive_data("AKIA1234567890ABCDEF") == "***"
Expand Down
7 changes: 4 additions & 3 deletions tests/test_required_workflow_queue_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def test_strix_cancels_superseded_pr_head_security_evidence() -> None:
assert "github.event.pull_request.base.repo.full_name" in concurrency_contract
assert "github.repository" in concurrency_contract
assert (
"strix-${{ github.event.inputs.target_repository || "
"strix-${{ github.event_name }}-${{ github.event.inputs.target_repository || "
"github.event.pull_request.base.repo.full_name || github.repository }}"
) in concurrency_contract
assert "format('pr-{0}', github.event.pull_request.number)" in concurrency_contract
Expand All @@ -70,6 +70,7 @@ def test_strix_cancels_superseded_pr_head_security_evidence() -> None:
assert "github.event.pull_request.head.sha" not in concurrency_contract
assert "github.event.inputs.pr_head_sha" not in concurrency_contract
assert "cancel-in-progress: true" in workflow
assert "manual workflow_dispatch evidence cannot cancel" in workflow
assert "PR-number scope keeps the queue on the current HEAD" in workflow
assert "refs/pull/<n>/head has already advanced before this queued run starts" in workflow

Expand Down Expand Up @@ -169,10 +170,10 @@ def test_noema_workflow_run_without_pull_request_skips_before_token_exchange() -

assert "Noema review skipped: no pull request number is associated with this event." in workflow
assert "if: env.PR_NUMBER == ''" in workflow
assert workflow.count("if: env.PR_NUMBER != ''") >= 4
assert workflow.count("if: env.PR_NUMBER != ''") >= 3


def test_noema_and_scheduler_trusted_checkouts_use_workflow_sha() -> None:
def test_noema_and_scheduler_trusted_checkouts_use_static_main() -> None:
noema = workflow_text("noema-review.yml")
scheduler = workflow_text("pr-review-merge-scheduler.yml")

Expand Down
Loading