audit-pattern-harness/

directory
v0.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 31, 2026 License: UNKNOWN not legal advice

README

Gno audit pattern harness

This directory contains the private-to-public audit pattern harness for sanitized finding families.

The durable repo split is:

  • misc/audit-pattern-harness: executable audit pattern harness, expected records, and fixtures.
  • docs/resources: builder-facing guidance promoted from stable findings.
  • examples/gno.land: compact public examples that demonstrate the safer contract pattern.

Run all current pattern slices:

make run AUDIT_PATTERN_FLAGS='-gno-bin /path/to/gno'

Development builds of gno may need GNOROOT:

GNOROOT=/path/to/gnolang/gno make run AUDIT_PATTERN_FLAGS='-gno-bin /path/to/gno'

Emit JSON:

go run ./cmd/auditpattern -format json ./expected/*.yaml

Read the default markdown report as follows:

  • status: PASS means every fixture matched its expected compile/test result and pattern-hit count.
  • gno test: want pass|fail, ok true|false compares the fixture's own Gno tests with the expected outcome.
  • pattern hits: got N, want N compares the rule's text-scan matches with the expected finding count.
  • listed file:line hits are the lines an auditor or agent should inspect before deciding whether the finding is real or a heuristic false positive.

Run the deterministic agent contract test:

go test ./internal/auditpattern -run TestAgentPatternContract

This test treats the guide files and expected records as the spec. It verifies that each pattern family is documented, has vulnerable and fixed fixtures, flags the vulnerable fixture, and leaves the fixed fixture clean. The compile-check variant runs automatically when GNO_BIN is set or gno is available on PATH; otherwise it skips with instructions.

CI does not run the compile-check. ci-dir-misc.yml runs go test for this module and installs no gno binary, so the variant above skips there — every time, silently, the way a skip does. What CI proves is that the rules and the record loader work, not that the fixtures still compile or still trip their rule. make run with a -gno-bin is what checks that, and it needs running by hand or by a job that builds gno first.

Expected records

Current pattern slices:

  • current-guard: cur.Previous() before cur.IsCurrent().
  • render-markdown: raw Render(path) markdown output.
  • payment-user-call: OriginSend() without an IsUserCall() guard.
  • origin-caller-auth: OriginCaller() used as authorization identity.
  • callback-param: caller-supplied callbacks accepted by realm APIs.
  • interface-realm-param: interfaces that expose cur realm.
  • exported-pointer-leak: exported pointers or pointer getters for mutable state.
  • render-map-iteration: public Render output that depends on map iteration order.
  • unsafe-previous-realm: unsafe.PreviousRealm() used in a realm that declares crossing functions (func F(cur realm, ...)).
  • pkg-mutable-pointer: pointer to a /p/ type with mutation methods (*avl.Tree) exposed as an exported return, field, or var.

Each expected/*.yaml record describes one finding family and its fixtures:

id: current-guard
title: cur.Previous without cur.IsCurrent
rule: current_guard
fixtures:
  - name: vulnerable
    path: ../fixtures/current-guard/vulnerable
    want_gno_test: pass
    want_pattern_hits: 1
  - name: fixed
    path: ../fixtures/current-guard/fixed
    want_gno_test: pass
    want_pattern_hits: 0

Paths are relative to the YAML file. want_gno_test is pass or fail. want_pattern_hits is the exact count expected from the rule.

Adding a pattern slice

  1. Add sanitized fixtures under fixtures/<slice>/.
  2. Add an expected/<slice>.yaml record.
  3. Teach internal/auditpattern the new rule.
  4. Promote stable, sanitized lessons to docs/resources and examples/gno.land when they are useful for builders.

Known limitations

Pattern detection is heuristic — the rules scan text, not an AST. Expect both false positives and false negatives in real-world code.

current_guard

Detects .Previous() before .IsCurrent() only within the same function. If the IsCurrent() check lives in a helper function called from the same function that calls .Previous(), the detector will not flag it. Check helper call chains manually when auditing cross-realm code.

payment_user_call

Flags any OriginSend() call not preceded by .IsUserCall() in the same function — this catches both the no-guard case and the wrong-guard case (IsUser() instead of IsUserCall()). The rule does not distinguish between the two; both appear as pattern hits.

render_markdown_escape

Flags return statements inside Render that contain the path variable without the word escape on the same line. Patterns using intermediate variable names (e.g. sanitized := md.EscapeText(path); return sanitized) are not flagged even when unsafe.

origin_caller_auth

Flags OriginCaller() only when it appears in a direct equality or inequality check. Benign logging reads are ignored, but an authorization check split across multiple lines or hidden behind a helper can be missed.

exported_pointer_leak

Flags exported package-level pointer variables and exported pointer-returning functions. Constructors shaped like NewX() *X { return &X{} } are ignored as fresh allocations; manually inspect constructors that may return aliases to shared package state.

render_map_iteration

Flags for ... range <m> inside Render where <m> is a package-level map variable, matched at a word boundary so a map scores does not flag an unrelated range scoresList. A map ranged behind a local alias, or built inside Render, is not detected.

unsafe_previous_realm

Flags PreviousRealm() calls only in files that also declare a crossing function (func F(cur realm, ...)). A non-crossing helper or a not-yet-migrated realm that legitimately uses chain/runtime/unsafe is not flagged. Detection is per file, so a crossing function in one file and the unsafe call in another (same package) are not correlated.

pkg_mutable_pointer

Flags a pointer to a /p/ type whose exported methods mutate the receiver, exposed as an exported function return, struct field, or package var. The known mutable type set is currently avl.Tree only; a pointer to another mutable /p/ type, or the type reached behind a local alias, is not detected. Getters returning a locally-declared *T are already covered by exported_pointer_leak.

Line reporting

Sources are gofmt-normalized before matching so irregular spacing cannot defeat the rules, but every hit's file:line and text are mapped back to the original on-disk source, so they stay accurate even on input that was not gofmt-clean.

Spec corpus test

TestAgentPatternContract verifies that each pattern family's required terms appear somewhere in the spec files. It confirms that the docs discuss the topic; it does not verify that the security advice in those docs is correct. Manual review is still required before promoting new guidance.

Directories

Path Synopsis
cmd
auditpattern command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL