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
47 changes: 27 additions & 20 deletions .github/workflows/secret-scanner-legacy.yml
Original file line number Diff line number Diff line change
@@ -1,28 +1,35 @@
# Canary safety: retained for Rust/shell coverage comparison; not scan / gitleaks.
# SPDX-License-Identifier: MPL-2.0
# Prevention workflow - scans for hardcoded secrets before they reach main.
#
# Calls the estate's shared secret scanner (gitleaks + rust-secrets +
# shell-secrets). The job key MUST stay `scan`: the estate-wide
# Secret-Scan-Floor ruleset requires the check context `scan / gitleaks`.
#
# No `secrets:` line, deliberately: the reusable references no secrets
# (gitleaks runs as a checksum-verified binary, not gitleaks-action), so
# `secrets: inherit` would only hand it every repo and org secret (CWE-250).
name: Legacy secret scanner (coverage comparison)

# Filename retained from the comparison canary. No moved-owner reusable,
# duplicate full-history Gitleaks pass, secret inheritance or policy expansion.
# The source ports are compared with a frozen pinned oracle by differential CI.
name: Supplemental secret checks
on:
pull_request:
push:
branches: [main]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

concurrency:
group: supplemental-secrets-${{ github.ref }}
cancel-in-progress: true
jobs:
legacy:
uses: hyperpolymath/standards/.github/workflows/secret-scanner-reusable.yml@74d2f66f575246cf6e313ae7775f44df6e097ff2
supplements:
name: ${{ matrix.language }} supplemental secrets
runs-on: ubuntu-24.04
timeout-minutes: 5
strategy:
fail-fast: false
matrix:
language: [rust, shell]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Scan using the maintained in-suite port
shell: bash
env:
LANGUAGE: ${{ matrix.language }}
run: |
set -euo pipefail
case "$LANGUAGE" in rust|shell) ;; *) exit 2 ;; esac
timeout --signal=TERM --kill-after=10s 90s bash "actions/secret-scan-check/$LANGUAGE-supplement.sh"
10 changes: 10 additions & 0 deletions .github/workflows/secret-scanner-self-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,21 @@ jobs:
yq '.' actions/secret-scan-check/action.yml >/dev/null
- name: Shell/control-flow fixtures and vacuous-scanner mutant
run: bash actions/secret-scan-check/test.sh
- name: Preserve pinned legacy Rust and shell detection without leaking values
run: bash tests/secret-scanner-supplements.sh
- name: Install the pinned real scanner
run: bash actions/secret-scan-check/install.sh "$RUNNER_TEMP/suite-gitleaks"
- name: Repeat fixtures against the real detector (not a stand-in)
env:
GITLEAKS_BIN: ${{ runner.temp }}/suite-gitleaks/gitleaks
run: bash actions/secret-scan-check/test.sh
- name: Production caller pin is already published on suite main
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
bash tests/published-scanner-pin.sh
ref=$(yq -r '.jobs.scan.uses' .github/workflows/secret-scanner.yml)
bash scripts/verify-published-scanner-pin.sh "${ref##*@}"
- name: Evidence collector controls
run: bash tests/inspect-pr-ci.sh
2 changes: 1 addition & 1 deletion .github/workflows/secret-scanner.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ concurrency:
cancel-in-progress: true
jobs:
scan:
uses: hyperpolymath/cicd-suite/.github/workflows/secret-scanner-reusable.yml@50dc27f47e39f7ac046596c071ed4ea80b4989e0
uses: hyperpolymath/cicd-suite/.github/workflows/secret-scanner-reusable.yml@d285b0a6f9bd85c7d678619dd6269437127dddb5
with:
# Keep false until an initial full audit passes and the security owner
# accepts introduced-commit PR coverage. All non-PR runs remain full.
Expand Down
18 changes: 18 additions & 0 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -433,3 +433,21 @@ is not claimed to reproduce its specialised Rust/shell heuristic checks.
Keep those protections until parity controls or an owner-approved migration
exist. The real-binary CI controls and a caller canary must pass before
production rollout; see link:docs/SECRET-SCANNER-ROLLOUT.adoc[rollout status].

==== Post-merge startup repair and supplemental detector ports

The follow-up described in
link:docs/SCANNER-STARTUP-AND-PARITY.adoc[Startup and supplemental coverage]
repins this repository to the published #62 merge commit. The initial
pre-merge pin failed resolution after merge; the canonical legacy dependency
was then explicitly refused by the caller's Actions admission policy.
Rather than broadening permissions, the suite now carries Rust/shell ports
and 26 differential fixtures against frozen legacy run bodies, plus five
hardening controls. The former legacy comparison workflow runs these local
checks; it no longer invokes standards or repeats full-history Gitleaks.

The new scanner source includes both ports in its composite verdict. Publish
that implementation before advancing consumer pins: the currently deployed
suite pin still selects the previously published scanner, while separate
local supplement jobs preserve this repository's supplementary checking.
No estate-wide rollout or whole-corpus equivalence is claimed by the fixtures.
13 changes: 13 additions & 0 deletions actions/secret-scan-check/check.sh
Original file line number Diff line number Diff line change
Expand Up @@ -132,5 +132,18 @@ for pass in tree history; do
*) verdict=2 ;;
esac
done
# Preserve the old bundle's unique Rust/shell heuristics. PR shell ignore
# policy comes from the trusted base, just like the Gitleaks configuration.
for language in rust shell; do
rc=0
(cd "$subject" && SHELL_IGNORE_FILE="$scan_dir/.shell-secrets-ignore" \
timeout --signal=TERM --kill-after=10s 90s bash "$script_dir/$language-supplement.sh") || rc=$?
printf 'supplement=%s exit=%s\n' "$language" "$rc"
case $rc in
0) ;;
1) [[ $verdict == 2 ]] || verdict=1 ;;
*) verdict=2 ;;
esac
done
printf 'verdict=%s (0=passed, 1=findings, 2=infrastructure/configuration/timeout)\n' "$verdict"
exit "$verdict"
142 changes: 142 additions & 0 deletions actions/secret-scan-check/rust-supplement.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: MPL-2.0
# Imported from metadatastician/standards secret-scanner-reusable.yml
# at 74d2f66f575246cf6e313ae7775f44df6e097ff2; findings output redacted.
# Preserve legacy heuristics pending corpus-backed replacement.
set -euo pipefail
ENFORCE_RUST_WIDE_SCAN_FROM=2026-08-21
TODAY=2026-08-21

# An unparseable cutoff would pick the warn branch forever, silently
# disarming the widened scan. Refuse to run instead.
require_date() {
case "$2" in
[0-9][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9]) : ;;
*) echo "::error::rust-secrets: $1='$2' is not YYYY-MM-DD."

Check warning on line 15 in actions/secret-scan-check/rust-supplement.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Assign this positional parameter to a local variable.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_cicd-suite&issues=AaGPOz4IYJKVmQ5dMVDN&open=AaGPOz4IYJKVmQ5dMVDN&pullRequest=64

Check warning on line 15 in actions/secret-scan-check/rust-supplement.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Assign this positional parameter to a local variable.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_cicd-suite&issues=AaGPOz4IYJKVmQ5dMVDM&open=AaGPOz4IYJKVmQ5dMVDM&pullRequest=64
echo "Refusing to run: an unparseable cutoff would disarm this gate."
exit 1 ;;
esac
}
require_date ENFORCE_RUST_WIDE_SCAN_FROM "$ENFORCE_RUST_WIDE_SCAN_FROM"
require_date RUST_TODAY "$TODAY"

manifest=$(find . -name Cargo.toml -not -path './target/*' -print -quit) || exit 2
if [[ -z $manifest ]]; then
echo 'No Cargo.toml found — skipping Rust secrets check'
exit 0
fi

# Scan every .rs file, not just ./src. A Cargo workspace keeps its
# code in crates/*/src, and the previous `grep … src/` matched
# nothing there: grep exits 2 on a missing directory, which the `if`
# read as "clean". Measured 2026-07-21 across the 64 Rust repos in
# the estate re-pin sweep: 8 (12.5%) have no root src/ and were
# therefore never scanned at all — a planted secret in
# crates/core/src/lib.rs passed this job silently.
population=$(mktemp) || exit 2
trap 'rm -f "$population"' EXIT
find . -name '*.rs' \
-not -path './target/*' -not -path '*/target/*' \
-not -path './vendor/*' -not -path '*/vendor/*' \
-not -path './.git/*' -print0 >"$population" || exit 2
mapfile -d '' -t FILES <"$population"

if [ ${#FILES[@]} -eq 0 ]; then

Check failure on line 44 in actions/secret-scan-check/rust-supplement.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_cicd-suite&issues=AaGPOz4IYJKVmQ5dMVDO&open=AaGPOz4IYJKVmQ5dMVDO&pullRequest=64
echo 'Cargo.toml present but no .rs files — nothing to scan'
exit 0
fi
echo "Scanning ${#FILES[@]} Rust file(s)."

# Each pattern requires an assignment DIRECTLY to a string literal of
# meaningful length. The previous forms matched `= ... "` — a quote
# anywhere after an equals — which flagged code that hardcodes
# nothing at all. Measured across the 64 Rust repos in the estate
# sweep, every one of these was a false positive:
# let api_key = request["api_key"].as_str().unwrap_or("") (lookup)
# let api_key_file = temp_dir.path().join("config.js") (path)
# Query::new("Here's my api_key=sk-12345") (a demo)
# A credential shorter than 8 characters is not a credential either.
# `static` is accepted alongside `const`: the old `const.*KEY` form
# missed `static AUTH_KEY: &str = "…"`, a genuine hardcoded secret
# (caught by canary, not by inspection).
PATTERNS=(
'(const|static)[[:space:]]+(mut[[:space:]]+)?[A-Za-z0-9_]*SECRET[A-Za-z0-9_]*[[:space:]]*(:[^=]*)?=[[:space:]]*b?"[^"]{8,}"'
'(const|static)[[:space:]]+(mut[[:space:]]+)?[A-Za-z0-9_]*KEY[A-Za-z0-9_]*[[:space:]]*(:[^=]*)?=[[:space:]]*b?"[a-zA-Z0-9]{16,}"'
'(const|static)[[:space:]]+(mut[[:space:]]+)?[A-Za-z0-9_]*TOKEN[A-Za-z0-9_]*[[:space:]]*(:[^=]*)?=[[:space:]]*b?"[^"]{8,}"'
'(let|static)[[:space:]]+(mut[[:space:]]+)?[a-z0-9_]*api_key[a-z0-9_]*[[:space:]]*(:[^=]*)?=[[:space:]]*b?"[^"]{8,}"'
'HMAC.*"[a-fA-F0-9]{32,}"'
'[a-z0-9_]*password[a-z0-9_]*[[:space:]]*(:[^=]*)?=[[:space:]]*b?"[^"]{8,}"'
)

# Exemptions, mirroring the four layers already documented on
# shell-secrets. All match on the VALUE or on an explicit pragma,
# never on a file path: a path-based exemption would blind the job
# to a genuine secret in the same file (the failure mode the
# .gitleaks.toml allowlist was rewritten to avoid, standards#512).
#
# 1. env-lookup RHS — `env::var("NAME")` IS the practice this job
# exists to enforce, so flagging it fails the correct code. This
# was the sole rust-secrets failure in the 201-repo sweep:
# cloudguard-server src/main.rs:59,
# `let api_key = env::var("CLOUDGUARD_API_KEY").ok();`. Anchored
# to the assignment and stopped at `;`, so a literal secret with
# an unrelated env::var mention later on the line still trips.
# 2. URL values — an OAuth endpoint is public and not a credential.
# `const MS_TOKEN_URL = "https://login.microsoftonline.com/…"`
# tripped `const.*TOKEN.*=.*"` in four places in one repo.
# 3. comment lines — documentation of a pattern is not a live secret.
# 4. inline pragma `// scanner-allow: rust-secrets`.
COMMENT='^[^:]*:[0-9][0-9]*:[[:space:]]*(//|/\*|\*)'
ENV_RHS='=[^;]*(env::var|env::var_os|std::env|env!\(|option_env!\(|from_env|dotenv)'
URL_RHS='=[[:space:]]*b?"(https?|wss?|ftp)://'
PRAGMA='scanner-allow:[[:space:]]*rust-secrets'

blocking=0
advisory=0
for pattern in "${PATTERNS[@]}"; do
rc=0
raw="$(grep -nHE "$pattern" "${FILES[@]}")" || rc=$?
[[ $rc == 0 || $rc == 1 ]] || { echo '::error::Rust scan could not read its population'; exit 2; }
hits="$(printf '%s\n' "$raw" \
| grep -vE "$COMMENT" \
| grep -vE "$ENV_RHS" \
| grep -vE "$URL_RHS" \
| grep -vE "$PRAGMA" || [ $? -eq 1 ])"

Check failure on line 104 in actions/secret-scan-check/rust-supplement.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_cicd-suite&issues=AaGPOz4IYJKVmQ5dMVDP&open=AaGPOz4IYJKVmQ5dMVDP&pullRequest=64
[ -n "$hits" ] || continue

Check failure on line 105 in actions/secret-scan-check/rust-supplement.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_cicd-suite&issues=AaGPOz4IYJKVmQ5dMVDQ&open=AaGPOz4IYJKVmQ5dMVDQ&pullRequest=64

# ./src was the only path the previous version scanned. Hits there
# keep blocking exactly as before — no regression. Hits outside it
# are newly visible, so they warn until the cutoff rather than
# reddening repos that were never actually being scanned.
old_scope="$(printf '%s\n' "$hits" | grep -E '^\./src/' || [ $? -eq 1 ])"

Check failure on line 111 in actions/secret-scan-check/rust-supplement.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_cicd-suite&issues=AaGPOz4IYJKVmQ5dMVDR&open=AaGPOz4IYJKVmQ5dMVDR&pullRequest=64
new_scope="$(printf '%s\n' "$hits" | grep -vE '^\./src/' || [ $? -eq 1 ])"

Check failure on line 112 in actions/secret-scan-check/rust-supplement.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_cicd-suite&issues=AaGPOz4IYJKVmQ5dMVDS&open=AaGPOz4IYJKVmQ5dMVDS&pullRequest=64

if [ -n "$old_scope" ]; then

Check failure on line 114 in actions/secret-scan-check/rust-supplement.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_cicd-suite&issues=AaGPOz4IYJKVmQ5dMVDT&open=AaGPOz4IYJKVmQ5dMVDT&pullRequest=64
printf '%s\n' "$old_scope" | sed -E 's/(:[0-9]+):.*/\1:[redacted]/'
echo "WARNING: Potential hardcoded secret found matching: $pattern"
blocking=1
fi
if [ -n "$new_scope" ]; then

Check failure on line 119 in actions/secret-scan-check/rust-supplement.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_cicd-suite&issues=AaGPOz4IYJKVmQ5dMVDU&open=AaGPOz4IYJKVmQ5dMVDU&pullRequest=64
printf '%s\n' "$new_scope" | sed -E 's/(:[0-9]+):.*/\1:[redacted]/'
if [[ "$TODAY" < "$ENFORCE_RUST_WIDE_SCAN_FROM" ]]; then
echo "::warning::Potential hardcoded secret outside ./src matching:" \
"$pattern — becomes BLOCKING on $ENFORCE_RUST_WIDE_SCAN_FROM (today is $TODAY)."
advisory=1
else
echo "WARNING: Potential hardcoded secret found matching: $pattern"
blocking=1
fi
fi
done

if [ "$blocking" -eq 1 ]; then

Check failure on line 132 in actions/secret-scan-check/rust-supplement.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_cicd-suite&issues=AaGPOz4IYJKVmQ5dMVDV&open=AaGPOz4IYJKVmQ5dMVDV&pullRequest=64
echo "::error::Potential hardcoded secrets detected. Use environment variables instead."
exit 1
fi
if [ "$advisory" -eq 1 ]; then

Check failure on line 136 in actions/secret-scan-check/rust-supplement.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_cicd-suite&issues=AaGPOz4IYJKVmQ5dMVDW&open=AaGPOz4IYJKVmQ5dMVDW&pullRequest=64
# Never claim a clean pass while findings are outstanding.
echo "NOT YET ENFORCED: findings outside ./src are advisory until $ENFORCE_RUST_WIDE_SCAN_FROM."
exit 0
fi
echo 'No hardcoded secrets detected in Rust sources.'

117 changes: 117 additions & 0 deletions actions/secret-scan-check/shell-supplement.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: MPL-2.0
# Imported from metadatastician/standards secret-scanner-reusable.yml
# at 74d2f66f575246cf6e313ae7775f44df6e097ff2; findings output redacted.
# Preserve legacy heuristics pending corpus-backed replacement.
set -euo pipefail
# Patterns: an `export FOO=` or `FOO=` with a quoted literal of meaningful length.
# Restricted to *_TOKEN / *_KEY / *_SECRET / PASSWORD to keep false-positives low.
PATTERNS=(
'(export[[:space:]]+)?[A-Z_]*TOKEN[A-Z_]*=["'"'"'][A-Za-z0-9_./+=-]{20,}["'"'"']'
'(export[[:space:]]+)?[A-Z_]*API_KEY[A-Z_]*=["'"'"'][A-Za-z0-9_./+=-]{20,}["'"'"']'
'(export[[:space:]]+)?[A-Z_]*SECRET[A-Z_]*=["'"'"'][A-Za-z0-9_./+=-]{16,}["'"'"']'
'(export[[:space:]]+)?PASSWORD=["'"'"'][^"'"'"']{6,}["'"'"']'
)

# Inline pragma patterns — suppress a hit when found on the same or
# immediately preceding line.
PRAGMA_RE='(scanner-allow:[[:space:]]*shell-secrets|hypatia:[[:space:]]*allow[[:space:]]+security_errors/secret_detected)'

# Param-expansion RHS pattern — assignments whose value is a variable
# reference rather than a literal are never real secrets.
# Matches: ="$VAR" ="${VAR}" ="${VAR:-…}" ="${VAR:?…}" ='${VAR}' =$VAR
PARAM_EXPANSION_RE='=['"'"'"'"'"']?\$\{?[A-Za-z_][A-Za-z0-9_]*(:[?-][^}]*)?\}?['"'"'"'"'"']?[[:space:]]*(#.*)?$'

# Load per-repo ignore globs from .shell-secrets-ignore if present.
IGNORE_GLOBS=()
ignore_file=${SHELL_IGNORE_FILE:-.shell-secrets-ignore}
if [[ -L $ignore_file || ( -e $ignore_file && ! -f $ignore_file ) ]]; then
echo "::error::invalid shell ignore file"; exit 2
fi
if [[ -f $ignore_file ]]; then
while IFS= read -r line || [[ -n "$line" ]]; do
# Skip blank lines and comments
[[ -z "$line" || "$line" == \#* ]] && continue
IGNORE_GLOBS+=("$line")
done < "$ignore_file"
fi

# is_ignored <filepath> — returns 0 (true) if path matches any ignore glob.
is_ignored() {
local path="$1"
for glob in "${IGNORE_GLOBS[@]}"; do
# Use bash pattern matching; strip leading ./ for consistency.
local stripped="${path#./}"
# shellcheck disable=SC2254
if [[ "$stripped" == $glob ]]; then
return 0
fi
done
return 1
}

matches=$(mktemp) || exit 2
trap 'rm -f "$matches"' EXIT
found=0
for pattern in "${PATTERNS[@]}"; do
rc=0
grep -rnE --include='*.sh' --include='*.bash' \
--exclude-dir='.git' --exclude-dir='node_modules' --exclude-dir='target' \
"$pattern" . >"$matches" || rc=$?
[[ $rc == 0 || $rc == 1 ]] || { echo '::error::shell scan could not read its population'; exit 2; }
# Collect raw matches: filepath:lineno:content
while IFS= read -r raw_match; do
[[ -z "$raw_match" ]] && continue

# Parse filepath and line number from grep -n output (file:line:content).
filepath="${raw_match%%:*}"
rest="${raw_match#*:}"
lineno="${rest%%:*}"
content="${rest#*:}"
[[ $lineno =~ ^[1-9][0-9]*$ ]] || { echo "::error::ambiguous shell finding location"; exit 2; }

# Exemption 1: .shell-secrets-ignore glob match on the file path.
if is_ignored "$filepath"; then
echo " [skip] $filepath:$lineno — matched .shell-secrets-ignore glob"
continue
fi

# Exemption 2: param-expansion RHS — value is a variable reference, not a literal.
if echo "$content" | grep -qE "$PARAM_EXPANSION_RE"; then
echo " [skip] $filepath:$lineno — param-expansion (not a literal value)"
continue
fi

# Exemption 3: comment line — leading non-whitespace char is '#'.
# Comment lines cannot hold real secrets; they only document patterns.
if echo "$content" | grep -qE '^[[:space:]]*#'; then
echo " [skip] $filepath:$lineno — comment line (not executable)"
continue
fi

# Exemption 5: inline pragma on same line.
if echo "$content" | grep -qE "$PRAGMA_RE"; then
echo " [skip] $filepath:$lineno — inline pragma on same line"
continue
fi

# Exemption 6: inline pragma on the immediately preceding line.
if [[ "$lineno" -gt 1 ]]; then
prev_line=$(sed -n "$((lineno - 1))p" "$filepath" 2>/dev/null)
if echo "$prev_line" | grep -qE "$PRAGMA_RE"; then
echo " [skip] $filepath:$lineno — pragma on preceding line"
continue
fi
fi

printf 'finding path=%q line=%s value=[redacted]\n' "$filepath" "$lineno"
echo " Potential hardcoded secret matching pattern: $pattern"
found=1

done < "$matches"
done

if [ $found -eq 1 ]; then

Check failure on line 114 in actions/secret-scan-check/shell-supplement.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_cicd-suite&issues=AaGPOz2YYJKVmQ5dMVDL&open=AaGPOz2YYJKVmQ5dMVDL&pullRequest=64
echo "::error::Hardcoded secret detected in a shell script. Read the value from the environment (e.g. \"\${MY_TOKEN:?}\") and supply it via a repo or org secret."
exit 1
fi
Loading
Loading