-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathaction.yml
More file actions
111 lines (102 loc) · 3.58 KB
/
Copy pathaction.yml
File metadata and controls
111 lines (102 loc) · 3.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# Rafter Security — GitHub Action
#
# Deterministic secret scanning for CI. 21+ credential patterns via Betterleaks,
# stable exit codes (0 = clean, 1 = findings, 2 = error), structured JSON output.
# No API key required. No code leaves the runner.
#
# Usage:
# - uses: Raftersecurity/rafter-cli@v1
# with:
# scan-path: '.'
#
# Exit codes:
# 0 — No secrets found
# 1 — Secrets detected (blocks the workflow)
# 2 — Scanner error (missing binary, bad config)
name: Rafter Security Scan
description: Deterministic secret scanning with stable exit codes and structured output — no API key required
branding:
icon: shield
color: black
inputs:
scan-path:
description: "Path to scan for secrets (default: repository root)"
required: false
default: '.'
args:
description: Additional arguments passed to `rafter secrets`
required: false
default: '--quiet'
version:
description: "Rafter CLI version to install (e.g. 0.6.5, latest)"
required: false
default: 'latest'
install-method:
description: "Installation method: npm or pip"
required: false
default: 'npm'
format:
description: "Output format: json or text"
required: false
default: 'json'
outputs:
finding-count:
description: Number of secrets found (0 if clean)
value: ${{ steps.scan.outputs.finding-count }}
report:
description: Full scan report (JSON when format=json)
value: ${{ steps.scan.outputs.report }}
exit-code:
description: Scanner exit code (0=clean, 1=findings, 2=error)
value: ${{ steps.scan.outputs.exit-code }}
runs:
using: composite
steps:
- name: Install Rafter CLI (npm)
if: inputs.install-method == 'npm'
shell: bash
run: |
if [ "${{ inputs.version }}" = "latest" ]; then
npm install -g @rafter-security/cli
else
npm install -g @rafter-security/cli@${{ inputs.version }}
fi
- name: Install Rafter CLI (pip)
if: inputs.install-method == 'pip'
shell: bash
run: |
if [ "${{ inputs.version }}" = "latest" ]; then
pip install rafter-cli
else
pip install rafter-cli==${{ inputs.version }}
fi
- name: Scan for secrets
id: scan
shell: bash
run: |
set +e
# Capture stdout (scan results) and stderr (status messages) separately
STDERR_FILE=$(mktemp)
OUTPUT=$(rafter secrets ${{ inputs.scan-path }} ${{ inputs.args }} --format ${{ inputs.format }} 2>"$STDERR_FILE")
EXIT_CODE=$?
STDERR_OUTPUT=$(cat "$STDERR_FILE")
rm -f "$STDERR_FILE"
set -e
echo "exit-code=${EXIT_CODE}" >> "$GITHUB_OUTPUT"
echo "report<<RAFTER_EOF" >> "$GITHUB_OUTPUT"
echo "${OUTPUT}" >> "$GITHUB_OUTPUT"
echo "RAFTER_EOF" >> "$GITHUB_OUTPUT"
# Count findings from output. rafter ≥0.7.0 wraps results in an object
# ({_note, scan_mode, triage_applied, results: [...]}); older versions
# emitted a bare array. Handle both so users pinning `version:` to an
# older release don't break.
if [ "${{ inputs.format }}" = "json" ]; then
COUNT=$(echo "${OUTPUT}" | jq '[(if type == "array" then . else .results end) | .[]?.matches[]?] | length' 2>/dev/null || echo "0")
else
COUNT=$(echo "${OUTPUT}" | grep -c 'Secret:' 2>/dev/null || echo "0")
fi
echo "finding-count=${COUNT}" >> "$GITHUB_OUTPUT"
# Show both stdout and stderr to the runner log
[ -n "$STDERR_OUTPUT" ] && echo "$STDERR_OUTPUT" >&2
echo "${OUTPUT}"
exit ${EXIT_CODE}