Repository navigation
Expand file tree
/
Copy pathaction.yml
More file actions
189 lines (182 loc) · 7.73 KB
/
Copy pathaction.yml
File metadata and controls
189 lines (182 loc) · 7.73 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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
name: "Causari Survival Audit"
description: >-
Zero-setup audit of AI code survival: how many lines from AI-tagged
commits are still alive at HEAD. AI-tagged is metadata, not proof a
model typed the line. Sticky PR comment + job summary.
Check out with full history (actions/checkout `fetch-depth: 0`): the
audit refuses shallow clones because a truncated history misstates
every count. Optionally verifies a PNX proof (crovia.pnx.v1) produced
in the job and attaches its verdict to the same comment.
author: "Crovia Trust"
branding:
icon: "activity"
color: "green"
inputs:
comment:
description: "Post the summary as a sticky PR comment (pull_request events only)"
required: false
default: "true"
version:
description: "Causari release tag to install (default: latest)"
required: false
default: "latest"
pnx-proof:
description: >-
Path of a PNX proof (crovia.pnx.v1, bare or inside a Crovia Seal) written
earlier in the job by `re pnx prove` or `tacet-pnx prove`. When set, the
proof is verified offline with `re pnx verify` and its verdict is appended
to the job summary and the PR comment. Empty: no PNX section.
required: false
default: ""
pnx-assets:
description: >-
Newline-separated protected assets the proof lists: `LABEL=PATH` entries
or directories (label = path relative to the directory). With them the
fingerprints are recomputed from the bytes; without them only the paths
of the listed keys are checked and the verdict carries a warning saying
so. Asset bytes never enter the summary or the comment.
required: false
default: ""
pnx-fail-on-present:
description: >-
Fail the step unless the proof is valid and every asset absent. Default
"false": only an invalid proof fails the step; a present, undetectable or
partially covered asset is reported and the step passes.
required: false
default: "false"
seal:
description: >-
Also issue a Crovia Seal (crovia.seal.v1) over the audit JSON, bound
to the audited commit and method version, written to
causari-audit.seal.json and uploaded as the `causari-audit-seal`
artifact. Anyone verifies it offline with `re seal verify FILE` or at
https://causari.dev/verify. Without `seal-key` the runner signs with a
key created for this run: the seal then proves the numbers were not
altered after the run, not who ran it.
required: false
default: "false"
seal-key:
description: >-
Hex-encoded 32-byte Ed25519 seed of a persistent issuer identity: the
contents of .causari/keys/seal-issuer.key after `re init` (public key
shown by `re seal issuer`). Pass it from a secret. Every run starts a
new chain at sequence 0 under this key unless .causari/seal/ is
restored between runs. Ignored unless `seal` is true.
required: false
default: ""
runs:
using: "composite"
steps:
- name: Install re
shell: bash
run: |
set -e
VERSION="${{ inputs.version }}"
TARGET="x86_64-unknown-linux-gnu"
if [ "$VERSION" = "latest" ]; then
VERSION="$(curl -fsSL https://api.github.com/repos/croviatrust/causari/releases/latest \
| sed -n 's/.*"tag_name": *"\([^"]*\)".*/\1/p' | head -n1)"
fi
BASE="https://github.com/croviatrust/causari/releases/download/$VERSION"
OK=0
for ASSET in "causari-$VERSION-$TARGET.tar.gz" "re-$VERSION-$TARGET.tar.gz"; do
echo "Downloading $BASE/$ASSET"
if [ -n "$VERSION" ] && curl -fsSL "$BASE/$ASSET" -o /tmp/causari.tar.gz; then
curl -fsSL "$BASE/SHA256SUMS.txt" -o /tmp/SHA256SUMS.txt
EXPECTED="$(grep " \*\{0,1\}$ASSET\$" /tmp/SHA256SUMS.txt | awk '{print $1}')"
ACTUAL="$(sha256sum /tmp/causari.tar.gz | awk '{print $1}')"
if [ -z "$EXPECTED" ] || [ "$EXPECTED" != "$ACTUAL" ]; then
echo "::error::checksum mismatch for $ASSET (expected '$EXPECTED', got '$ACTUAL')"; exit 1
fi
sudo tar -C /usr/local/bin -xzf /tmp/causari.tar.gz
OK=1
break
fi
done
if [ "$OK" != "1" ]; then
echo "Prebuilt binary unavailable; falling back to cargo install (slow)."
cargo install --git https://github.com/croviatrust/causari --locked
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
fi
- name: Install seal issuer key
if: inputs.seal == 'true' && inputs['seal-key'] != ''
shell: bash
env:
SEAL_KEY: ${{ inputs['seal-key'] }}
# `re audit --seal` signs with the audited repository's own issuer
# identity (.causari/keys/seal-issuer.key), creating one when absent.
# Seeding the file first makes every run sign under the same key.
run: |
set -e
case "$SEAL_KEY" in
*[!0-9a-fA-F]*|'') echo "::error::seal-key must be 64 hex characters"; exit 1 ;;
esac
[ "${#SEAL_KEY}" = "64" ] || { echo "::error::seal-key must be 64 hex characters (got ${#SEAL_KEY})"; exit 1; }
mkdir -p .causari/keys
(umask 077; printf '%s' "$SEAL_KEY" > .causari/keys/seal-issuer.key)
- name: Run survival audit
shell: bash
# Needs the full history: `actions/checkout` defaults to fetch-depth 1,
# which `re audit` refuses. Set `fetch-depth: 0` on the checkout step.
# With `seal`, the bundle is written next to the summary and the
# summary ends with one paragraph naming the seal.
run: |
set -o pipefail
if [ "${{ inputs.seal }}" = "true" ]; then
re audit --summary --seal --output causari-audit.seal.json | tee causari-audit.md
else
re audit --summary | tee causari-audit.md
fi
cat causari-audit.md >> "$GITHUB_STEP_SUMMARY"
- name: Verify PNX proof
if: inputs.pnx-proof != ''
shell: bash
env:
PNX_PROOF: ${{ inputs.pnx-proof }}
PNX_ASSETS: ${{ inputs.pnx-assets }}
PNX_FAIL_ON_PRESENT: ${{ inputs.pnx-fail-on-present }}
# Exit codes of `re pnx verify` (same as tacet-pnx): 0 valid and every
# asset absent, 1 valid but an asset present / undetectable / partial,
# 2 invalid. The section goes into the same file as the audit so the
# sticky comment carries both.
run: |
set +e
ARGS=()
while IFS= read -r line; do
line="${line#"${line%%[![:space:]]*}"}"
[ -z "$line" ] && continue
if [ -d "$line" ]; then ARGS+=(--assets-dir "$line"); else ARGS+=(--asset "$line"); fi
done <<< "$PNX_ASSETS"
NO_COLOR=1 re pnx verify "$PNX_PROOF" ${ARGS[@]+"${ARGS[@]}"} > pnx-verify.txt 2>&1
CODE=$?
cat pnx-verify.txt
{
echo
echo "## PNX — Proof of Non-Exfiltration"
echo
echo '```'
cat pnx-verify.txt
echo '```'
} > pnx-section.md
cat pnx-section.md >> causari-audit.md
cat pnx-section.md >> "$GITHUB_STEP_SUMMARY"
if [ "$CODE" -eq 2 ]; then
echo "::error::PNX proof $PNX_PROOF is invalid or unverifiable"; exit 2
fi
if [ "$CODE" -eq 1 ] && [ "$PNX_FAIL_ON_PRESENT" = "true" ]; then
echo "::error::PNX proof $PNX_PROOF is valid but not every asset is proven absent"; exit 1
fi
exit 0
- name: Upload audit seal
if: inputs.seal == 'true'
uses: actions/upload-artifact@v4
with:
name: causari-audit-seal
path: causari-audit.seal.json
if-no-files-found: error
- name: Comment on PR
if: inputs.comment == 'true' && github.event_name == 'pull_request'
uses: marocchino/sticky-pull-request-comment@v3
with:
header: causari-audit
path: causari-audit.md