-
Notifications
You must be signed in to change notification settings - Fork 0
feat: implement issue #355 — Compliance: secret_scanning_ai_detection #435
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
77ef66e
feat: implement issue #355 — Compliance: secret_scanning_ai_detection
donpetry-bot 431aba0
chore: apply manual instructions [skip ci-relay]
donpetry-bot 7fb4c45
chore: apply manual instructions [skip ci-relay]
donpetry-bot 270953e
Merge branch 'main' into dev-lead/issue-355-20260610-1424
don-petry 646625c
fix(ci): use curl for gitleaks download — GITHUB_TOKEN 401s on extern…
donpetry-bot 0c3d839
Merge branch 'main' into dev-lead/issue-355-20260610-1424
don-petry 17e019e
Merge branch 'main' into dev-lead/issue-355-20260610-1424
don-petry fb6f917
Merge branch 'main' into dev-lead/issue-355-20260610-1424
don-petry 050d6d4
Merge branch 'main' into dev-lead/issue-355-20260610-1424
don-petry 5218394
fix(ci): auto-fix for SonarCloud Code Analysis [skip ci-relay]
donpetry-bot 6a7c48f
Merge branch 'main' into dev-lead/issue-355-20260610-1424
don-petry adb9d2f
Merge branch 'main' into dev-lead/issue-355-20260610-1424
don-petry e1de4f4
Merge branch 'main' into dev-lead/issue-355-20260610-1424
don-petry 95733b4
Merge branch 'main' into dev-lead/issue-355-20260610-1424
don-petry 3b92806
Merge branch 'main' into dev-lead/issue-355-20260610-1424
don-petry 0dff6ac
Merge branch 'main' into dev-lead/issue-355-20260610-1424
don-petry 21e9ea6
Merge branch 'main' into dev-lead/issue-355-20260610-1424
don-petry f8f6d8e
Merge branch 'main' into dev-lead/issue-355-20260610-1424
don-petry 458a17d
Merge branch 'main' into dev-lead/issue-355-20260610-1424
don-petry eb0f347
Merge branch 'main' into dev-lead/issue-355-20260610-1424
don-petry fcb69ae
Merge branch 'main' into dev-lead/issue-355-20260610-1424
don-petry 449e676
Merge branch 'main' into dev-lead/issue-355-20260610-1424
don-petry affb226
Merge branch 'main' into dev-lead/issue-355-20260610-1424
don-petry 7f1746e
Merge branch 'main' into dev-lead/issue-355-20260610-1424
don-petry 80cdbbe
fix(bot): address bot feedback [skip ci-relay]
donpetry-bot 8d774a9
chore: apply manual instructions [skip ci-relay]
donpetry-bot c7677b2
Merge branch 'main' into dev-lead/issue-355-20260610-1424
don-petry ff53175
Merge branch 'main' into dev-lead/issue-355-20260610-1424
don-petry 5882f65
Merge branch 'main' into dev-lead/issue-355-20260610-1424
donpetry-bot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| #!/usr/bin/env bash | ||
| # Common test helpers for scripts/lib bats suites. | ||
|
|
||
| TT_REPO_ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../../../.." && pwd)" | ||
| export TT_REPO_ROOT | ||
|
|
||
| TT_SCRIPTS_LIB_DIR="${TT_REPO_ROOT}/scripts/lib" | ||
| export TT_SCRIPTS_LIB_DIR | ||
|
|
||
| tt_make_tmpdir() { | ||
| TT_TMP="$(mktemp -d)" | ||
| export TT_TMP | ||
| } | ||
|
|
||
| tt_cleanup_tmpdir() { | ||
| if [ -n "${TT_TMP:-}" ] && [ -d "${TT_TMP}" ]; then | ||
| rm -rf "${TT_TMP}" | ||
| fi | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,208 @@ | ||
| #!/usr/bin/env bats | ||
| # Tests for scripts/lib/push-protection.sh — pp_check_security_and_analysis() | ||
| # | ||
| # Covers the plan-gated feature handling: warning-severity settings whose API | ||
| # status is null (absent from the response) must NOT generate a finding, since | ||
| # a null status indicates the org plan does not support the feature and there | ||
| # is nothing the operator can do to remediate it. | ||
|
|
||
| load 'helpers/setup' | ||
|
|
||
| # --------------------------------------------------------------------------- | ||
| # Helpers: build repo-API JSON payloads | ||
| # --------------------------------------------------------------------------- | ||
|
|
||
| # Build the full repo JSON object that gh api "repos/ORG/REPO" returns. | ||
| # Accepts an inline security_and_analysis JSON fragment as $1. | ||
| # The mock gh_api then applies ".security_and_analysis // {}" to this object. | ||
| make_repo_json() { | ||
| local sa_json="$1" | ||
| printf '{"security_and_analysis":%s}' "$sa_json" | ||
| } | ||
|
|
||
| # --------------------------------------------------------------------------- | ||
| # Test setup / teardown | ||
| # --------------------------------------------------------------------------- | ||
|
|
||
| setup() { | ||
| tt_make_tmpdir | ||
|
|
||
| # Log file for add_finding calls — each call appends one line: | ||
| # "<repo>|<category>|<check>|<severity>|<detail>" | ||
| FINDINGS_LOG="${TT_TMP}/findings.log" | ||
| export FINDINGS_LOG | ||
|
|
||
| # Default: gh_api returns a fully-compliant security_and_analysis object | ||
| # wrapped in the full repo JSON so the jq filter ".security_and_analysis // {}" | ||
| # resolves correctly. | ||
| GH_API_RESPONSE="$(make_repo_json '{"secret_scanning":{"status":"enabled"},"secret_scanning_push_protection":{"status":"enabled"},"secret_scanning_ai_detection":{"status":"enabled"},"secret_scanning_non_provider_patterns":{"status":"enabled"},"dependabot_security_updates":{"status":"enabled"}}')" | ||
| export GH_API_RESPONSE | ||
|
|
||
| # Second-call response for the secret-scanning alerts proxy check | ||
| # (used only when the primary call returns {}). | ||
| GH_API_ALERTS_RESPONSE='[]' | ||
| export GH_API_ALERTS_RESPONSE | ||
|
|
||
| ORG="test-org" | ||
| export ORG | ||
|
|
||
| # Track how many times gh_api has been called so we can return different | ||
| # responses for the primary (repo) call vs. the proxy (alerts) call. | ||
| GH_API_CALL_COUNT=0 | ||
| export GH_API_CALL_COUNT | ||
|
|
||
| gh_api() { | ||
| GH_API_CALL_COUNT=$((GH_API_CALL_COUNT + 1)) | ||
| local endpoint="$1"; shift | ||
| local jq_filter="" | ||
| while [ $# -gt 0 ]; do | ||
| if [ "$1" = "--jq" ] && [ $# -gt 1 ]; then | ||
| jq_filter="$2"; shift 2 | ||
| else | ||
| shift | ||
| fi | ||
| done | ||
| # First call is always the primary repo endpoint. | ||
| # Subsequent calls are the alerts proxy. | ||
| local response | ||
| if [ "$GH_API_CALL_COUNT" -eq 1 ]; then | ||
| response="$GH_API_RESPONSE" | ||
| else | ||
| response="$GH_API_ALERTS_RESPONSE" | ||
| fi | ||
| if [ -n "$jq_filter" ]; then | ||
| printf '%s' "$response" | jq -r "$jq_filter" 2>/dev/null || echo "{}" | ||
| else | ||
| printf '%s' "$response" | ||
| fi | ||
| } | ||
| export -f gh_api | ||
|
|
||
| add_finding() { | ||
| local repo="$1" category="$2" check="$3" severity="$4" detail="$5" | ||
| printf '%s|%s|%s|%s|%s\n' "$repo" "$category" "$check" "$severity" "$detail" \ | ||
| >>"$FINDINGS_LOG" | ||
| } | ||
| export -f add_finding | ||
|
|
||
| # shellcheck source=/dev/null | ||
| . "${TT_SCRIPTS_LIB_DIR}/push-protection.sh" | ||
| } | ||
|
|
||
| teardown() { | ||
| tt_cleanup_tmpdir | ||
| } | ||
|
|
||
| findings() { | ||
| if [ -f "$FINDINGS_LOG" ]; then | ||
| cat "$FINDINGS_LOG" | ||
| else | ||
| echo "" | ||
| fi | ||
| } | ||
|
|
||
| finding_count() { | ||
| if [ -f "$FINDINGS_LOG" ]; then | ||
| wc -l < "$FINDINGS_LOG" | tr -d ' ' | ||
| else | ||
| echo "0" | ||
| fi | ||
| } | ||
|
|
||
| # --------------------------------------------------------------------------- | ||
| # Fully-compliant repo — no findings expected | ||
| # --------------------------------------------------------------------------- | ||
|
|
||
| @test "pp_check_security_and_analysis: no findings when all settings are enabled" { | ||
| pp_check_security_and_analysis "my-repo" | ||
| [ "$(finding_count)" -eq 0 ] | ||
| } | ||
|
|
||
| # --------------------------------------------------------------------------- | ||
| # warning-severity, null actual → plan does not support feature → no finding | ||
| # --------------------------------------------------------------------------- | ||
|
|
||
| @test "pp_check_security_and_analysis: secret_scanning_ai_detection absent emits no finding (plan-gated)" { | ||
| GH_API_RESPONSE="$(make_repo_json '{"secret_scanning":{"status":"enabled"},"secret_scanning_push_protection":{"status":"enabled"},"dependabot_security_updates":{"status":"enabled"}}')" | ||
| pp_check_security_and_analysis "my-repo" | ||
| if grep -q "secret_scanning_ai_detection" "$FINDINGS_LOG" 2>/dev/null; then | ||
| echo "unexpected finding for secret_scanning_ai_detection when status is absent" >&2 | ||
| false | ||
| fi | ||
| } | ||
|
|
||
| @test "pp_check_security_and_analysis: secret_scanning_non_provider_patterns absent emits no finding (plan-gated)" { | ||
| GH_API_RESPONSE="$(make_repo_json '{"secret_scanning":{"status":"enabled"},"secret_scanning_push_protection":{"status":"enabled"},"secret_scanning_ai_detection":{"status":"enabled"},"dependabot_security_updates":{"status":"enabled"}}')" | ||
| pp_check_security_and_analysis "my-repo" | ||
| if grep -q "secret_scanning_non_provider_patterns" "$FINDINGS_LOG" 2>/dev/null; then | ||
| echo "unexpected finding for secret_scanning_non_provider_patterns when status is absent" >&2 | ||
| false | ||
| fi | ||
| } | ||
|
|
||
| @test "pp_check_security_and_analysis: dependabot_security_updates absent emits no finding (warning, plan-gated)" { | ||
| GH_API_RESPONSE="$(make_repo_json '{"secret_scanning":{"status":"enabled"},"secret_scanning_push_protection":{"status":"enabled"},"secret_scanning_ai_detection":{"status":"enabled"},"secret_scanning_non_provider_patterns":{"status":"enabled"}}')" | ||
| pp_check_security_and_analysis "my-repo" | ||
| if grep -q "dependabot_security_updates" "$FINDINGS_LOG" 2>/dev/null; then | ||
| echo "unexpected finding for dependabot_security_updates when status is absent" >&2 | ||
| false | ||
| fi | ||
| } | ||
|
|
||
| # --------------------------------------------------------------------------- | ||
| # warning-severity, disabled actual → feature exists but off → finding emitted | ||
| # --------------------------------------------------------------------------- | ||
|
|
||
| @test "pp_check_security_and_analysis: secret_scanning_ai_detection disabled emits a warning finding" { | ||
| GH_API_RESPONSE="$(make_repo_json '{"secret_scanning":{"status":"enabled"},"secret_scanning_push_protection":{"status":"enabled"},"secret_scanning_ai_detection":{"status":"disabled"},"secret_scanning_non_provider_patterns":{"status":"enabled"},"dependabot_security_updates":{"status":"enabled"}}')" | ||
| pp_check_security_and_analysis "my-repo" | ||
| grep -q "secret_scanning_ai_detection" "$FINDINGS_LOG" | ||
| grep -q "|warning|" "$FINDINGS_LOG" | ||
| } | ||
|
|
||
| @test "pp_check_security_and_analysis: secret_scanning_non_provider_patterns disabled emits a warning finding" { | ||
| GH_API_RESPONSE="$(make_repo_json '{"secret_scanning":{"status":"enabled"},"secret_scanning_push_protection":{"status":"enabled"},"secret_scanning_ai_detection":{"status":"enabled"},"secret_scanning_non_provider_patterns":{"status":"disabled"},"dependabot_security_updates":{"status":"enabled"}}')" | ||
| pp_check_security_and_analysis "my-repo" | ||
| grep -q "secret_scanning_non_provider_patterns" "$FINDINGS_LOG" | ||
| } | ||
|
|
||
| # --------------------------------------------------------------------------- | ||
| # error-severity, null actual → always emits a finding (not plan-gated) | ||
| # --------------------------------------------------------------------------- | ||
|
|
||
| @test "pp_check_security_and_analysis: secret_scanning absent emits an error finding" { | ||
| GH_API_RESPONSE="$(make_repo_json '{"secret_scanning_push_protection":{"status":"enabled"},"secret_scanning_ai_detection":{"status":"enabled"},"secret_scanning_non_provider_patterns":{"status":"enabled"},"dependabot_security_updates":{"status":"enabled"}}')" | ||
| pp_check_security_and_analysis "my-repo" | ||
| grep -q "secret_scanning" "$FINDINGS_LOG" | ||
| grep -q "|error|" "$FINDINGS_LOG" | ||
| } | ||
|
|
||
| @test "pp_check_security_and_analysis: secret_scanning_push_protection absent emits an error finding" { | ||
| GH_API_RESPONSE="$(make_repo_json '{"secret_scanning":{"status":"enabled"},"secret_scanning_ai_detection":{"status":"enabled"},"secret_scanning_non_provider_patterns":{"status":"enabled"},"dependabot_security_updates":{"status":"enabled"}}')" | ||
| pp_check_security_and_analysis "my-repo" | ||
| grep -q "secret_scanning_push_protection" "$FINDINGS_LOG" | ||
| grep -q "|error|" "$FINDINGS_LOG" | ||
| } | ||
|
|
||
| # --------------------------------------------------------------------------- | ||
| # error-severity, disabled actual → always emits a finding | ||
| # --------------------------------------------------------------------------- | ||
|
|
||
| @test "pp_check_security_and_analysis: secret_scanning disabled emits an error finding" { | ||
| GH_API_RESPONSE="$(make_repo_json '{"secret_scanning":{"status":"disabled"},"secret_scanning_push_protection":{"status":"enabled"},"secret_scanning_ai_detection":{"status":"enabled"},"secret_scanning_non_provider_patterns":{"status":"enabled"},"dependabot_security_updates":{"status":"enabled"}}')" | ||
| pp_check_security_and_analysis "my-repo" | ||
| grep -q "secret_scanning" "$FINDINGS_LOG" | ||
| grep -q "|error|" "$FINDINGS_LOG" | ||
| } | ||
|
|
||
| # --------------------------------------------------------------------------- | ||
| # All plan-gated warning settings absent — no findings from those keys | ||
| # --------------------------------------------------------------------------- | ||
|
|
||
| @test "pp_check_security_and_analysis: no findings when only error settings are present and compliant" { | ||
| # Only the two required (error-severity) settings are present and enabled. | ||
| # All three warning-severity settings are absent (plan-gated). | ||
| GH_API_RESPONSE="$(make_repo_json '{"secret_scanning":{"status":"enabled"},"secret_scanning_push_protection":{"status":"enabled"}}')" | ||
| pp_check_security_and_analysis "my-repo" | ||
| [ "$(finding_count)" -eq 0 ] | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.