Repository navigation
Expand file tree
/
Copy pathMakefile
More file actions
206 lines (176 loc) · 8.64 KB
/
Copy pathMakefile
File metadata and controls
206 lines (176 loc) · 8.64 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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
BINARY := assay
PKG := ./...
CONTRACTS := assay-contracts
WASM := $(CONTRACTS)/out/assay_safety_registry.wasm
# Deployment coordinates. CONTRACT_ID is the live testnet deployment recorded in
# docs/deployment.md; override it to point the attest/read targets elsewhere.
NETWORK ?= testnet
SOURCE ?= assay-attester
CONTRACT_ID ?= CBK4FBIHMDTXCUPE4E3ZDVSFJSCY5FJETTKNIQPN4LFJIKKIBLKIXQ73
.PHONY: all build build-release test test-notify test-preimage test-reproducibility cover lint fmt vet run clean \
offline-test \
contract-test contract-lint contract-build \
build-contract deploy-testnet attest read verify-gate verify-wasm \
eval-record eval-compare
all: build
build:
go build -o $(BINARY) ./cmd/assay
# build-release builds the scanner under the flags that make the binary
# reproducible from any directory on any machine:
#
# -trimpath removes absolute file system paths from the binary
# -buildvcs=false removes the working tree's VCS state (a dirty checkout
# would otherwise stamp vcs.modified=true)
# CGO_ENABLED=0 removes the host C toolchain as an input
#
# The Go toolchain is pinned by go.mod, so the two inputs left are the source
# and the flags. CI proves the property by building this target twice in
# different directories and comparing hashes; see CONTRIBUTING.md
# ("Reproducible scanner builds").
#
# Note: this does not stamp a version. A build from a checkout reports
# ScannerIdentity "devel"; tagged releases are built by
# .github/workflows/release.yml with `go install ...@<tag>`, which stamps the
# tag. That split is deliberate: reproducibility of the local build and
# version binding of a release are separate guarantees.
build-release:
CGO_ENABLED=0 go build -trimpath -buildvcs=false -o $(BINARY) ./cmd/assay
test:
go test -race $(PKG)
# test-notify exercises scripts/notify-scheduled-failure.sh against a stubbed
# gh, covering open/update/comment/close and the "exactly one issue" rule. CI
# runs it alongside the merge-gate tests.
test-notify:
bash ./scripts/test-notify-scheduled-failure.sh
# test-reproducibility exercises scripts/reproducibility.sh against a stubbed
# assay binary and fixture tables, covering the PASS/MISMATCH/ENCODING/
# INCONCLUSIVE outcomes, their exit-code precedence, and the refusal of a
# table without a valid Preimage column. It needs no network, so CI runs it
# even though the script it tests does.
test-reproducibility:
bash ./scripts/test-reproducibility.sh
# test-preimage runs the independent Python encoder (written from
# docs/contract-interface.md alone) against the Go encoder over every committed
# vector, every internal/mechanics/testdata subject, and the language-neutral
# conformance cases. CI runs this as its own job; a deliberate encoding change
# fails here until the specification and both implementations agree.
test-preimage:
go test ./internal/attest/ -run IndependentEncoder -v
# cover prints the same per-package table CI puts in the job summary
# (scripts/coverage-report.sh), lowest coverage first. It reports; it does not
# gate. The test exit status is preserved so a failing test still fails.
cover:
@go test -covermode=atomic -coverprofile=coverage.out $(PKG) > coverage.log 2>&1; \
rc=$$?; cat coverage.log; echo; \
./scripts/coverage-report.sh coverage.log coverage.out; \
exit $$rc
fmt:
gofmt -w .
vet:
go vet $(PKG)
lint:
golangci-lint run
run: build
./$(BINARY) serve
contract-test:
cd $(CONTRACTS) && cargo test
contract-lint:
cd $(CONTRACTS) && cargo fmt --all -- --check
cd $(CONTRACTS) && cargo clippy --all-targets -- -D warnings
contract-build:
cd $(CONTRACTS) && cargo build --release --target wasm32v1-none
# build-contract produces the deployable artifact. It goes through the stellar
# CLI rather than cargo because the CLI also runs the wasm optimizer and checks
# the exported interface; contract-build above is the plain compile.
build-contract:
stellar contract build --manifest-path $(CONTRACTS)/Cargo.toml \
--package assay-safety-registry --out-dir $(CONTRACTS)/out
# verify-wasm rebuilds each contract from the committed source and checks the
# result against the wasm hashes recorded in docs/deployment.md. It builds into
# a temporary directory, so it never disturbs the artifact deploy-testnet would
# upload, and it never edits the document or submits a transaction.
#
# It exits 0 only when every recorded hash is reproduced. Until
# assay-contracts/rust-toolchain.toml exists (#127) the toolchain is whatever
# rustup has installed, which does not determine the bytes, so the run reports
# UNVERIFIABLE and exits 2. That is the honest answer, not a failure of the
# source. See docs/deployment.md ("Does the source still build what is
# deployed?").
verify-wasm:
./scripts/verify-wasm-source.sh
deploy-testnet: build-contract
stellar contract deploy --wasm $(WASM) \
--source-account $(SOURCE) --network $(NETWORK)
@echo
@echo "Deployed. Record the contract ID in docs/deployment.md, then run:"
@echo " stellar contract invoke --id <ID> --source-account $(SOURCE) \\"
@echo " --network $(NETWORK) -- init --admin \$$(stellar keys address $(SOURCE))"
# attest scans ASSET live and writes the result on-chain.
#
# Every number submitted comes from `assay attestation`, which derives severity,
# the mechanic bitset, and evidence_hash from that scan. Nothing here lets a
# hand-written value reach the contract.
attest: build
@test -n "$(ASSET)" || { echo 'usage: make attest ASSET=CODE-ISSUER'; exit 2; }
@set -eu; \
params=$$(./$(BINARY) attestation -raw '$(ASSET)'); \
severity=$$(printf '%s' "$$params" | cut -f1); \
flags=$$(printf '%s' "$$params" | cut -f2); \
hash=$$(printf '%s' "$$params" | cut -f3); \
sac=$$(stellar contract id asset --asset "$$(printf '%s' '$(ASSET)' | sed 's/-/:/')" --network $(NETWORK)); \
echo "$(ASSET)"; \
echo " sac $$sac"; \
echo " severity $$severity"; \
echo " flags $$flags"; \
echo " evidence $$hash"; \
stellar contract invoke --id $(CONTRACT_ID) --source-account $(SOURCE) --network $(NETWORK) \
-- attest --asset "$$sac" --severity "$$severity" --flags "$$flags" --evidence_hash "$$hash"
# read calls get_safety against the deployed contract. It simulates rather than
# submits, so reading an attestation costs nothing and needs no signature.
read:
@test -n "$(ASSET)" || { echo 'usage: make read ASSET=CODE-ISSUER'; exit 2; }
@set -eu; \
sac=$$(stellar contract id asset --asset "$$(printf '%s' '$(ASSET)' | sed 's/-/:/')" --network $(NETWORK)); \
echo "$(ASSET) -> $$sac"; \
stellar contract invoke --id $(CONTRACT_ID) --source-account $(SOURCE) --network $(NETWORK) \
--send=no -- get_safety --asset "$$sac"
# Runs the merge gate against a commit range, the same script CI runs on every
# PR. Verify a change offline before opening the PR:
# make verify-gate BASE=main HEAD=HEAD
verify-gate:
@test -n "$(BASE)" || { echo 'usage: make verify-gate BASE=<sha-or-ref> HEAD=<sha-or-ref>'; exit 2; }
./scripts/merge-gate.sh "$(BASE)" "$(HEAD)"
test-gate:
bash ./scripts/test-merge-gate.sh
# Records the labelled corpus's classification, per subject and per check.
# Commit the result when the classifier's output is intended to change; it is
# the baseline eval-compare diffs against.
eval-record:
go run ./cmd/eval -out docs/eval-baseline.json
# Re-captures one corpus fixture from the URLs recorded in PROVENANCE.md and
# prints a diff, so a maintainer can judge whether a moved verdict reflects a
# real change or a regression. It needs network access, so it is deliberately
# not part of `make test` or CI. A fetch that fails writes nothing.
#
# make refresh-fixture SUBJECT=aqua-clear-verified
# make refresh-fixture SUBJECT=aqua-clear-verified DRY_RUN=1
refresh-fixture:
@test -n "$(SUBJECT)" || { echo 'usage: make refresh-fixture SUBJECT=<fixture-dir>'; exit 2; }
go run ./cmd/refreshfixture -subject "$(SUBJECT)" $(if $(DRY_RUN),-dry-run,)
# Compares the current classifier against the recorded baseline and reports
# what moved: severity, mechanics and evidence separately, with undetermined
# subjects and corpus membership changes reported on their own. Exits 0 on a
# movement so it can be read as a report; add STRICT=1 to make movement fail.
eval-compare:
@go run ./cmd/eval -compare docs/eval-baseline.json $(if $(STRICT),-strict,)
# Prints the confusion matrix over the labelled corpus, showing agreements
# and disagreements per severity level and per check with undetermined as
# its own outcome class. Sample size is printed with every result.
# Precision and recall require -precision-recall and carry a sample-size
# caveat.
eval:
@go run ./cmd/eval -confusion -precision-recall
clean:
rm -f $(BINARY) coverage.out coverage.html coverage.log
rm -rf $(CONTRACTS)/out
cd $(CONTRACTS) && cargo clean