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
10 changes: 8 additions & 2 deletions .github/ci-evidence.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"inputs: the module pins; the script that pins the Runtime, earlier Runtime, old Runner and Gateway commits",
"the integration tests run against; the scripts that fail when a named real-companion test does not run and",
"pass; the toolchain check and the workflow naming the release toolchain; the runner whose summary is read;",
"the Release contents scripts and the packer's configuration."
"the Release contents scripts and the packer's configuration.",
"The selected retained-column Runtime has its own exact commit/release pin in build-pinned.sh; selected lifecycle and installed Spec identities below are part of this evidence."
],
"schema": 2,
"repository": "Judgment-Pack/judgment-pack-runner",
Expand All @@ -25,7 +26,12 @@
"tools/third_party_notices.py",
"tools/release_archives.py",
"tools/test_release_archives.py",
".goreleaser.yml"
".goreleaser.yml",
"internal/runner/column_role_v1.go",
"internal/runner/column_role_v1_lifecycle_test.go",
"internal/runner/column_rc2_core_test.go",
"internal/retainedcolumns/testdata/rc2/release-identity.json",
"internal/retainedcolumns/testdata/rc2/release-inventory.json"
],
"fresh_at_release": [
"tag syntax, tag names the commit, commit on main",
Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,10 @@ validation output, sample inputs/output, and a digest-pinned copy of the Runtime
executable. A job's only revision in this pilot is revision 1. Later edits to a pack
cannot change an existing job. Create and review a new job for changed policy.
The evaluator is Runtime's **experimental JPS 0.2.0-draft** contract, outputVersion 2;
this package does not expand Runtime's conformance claim or approve external action.
the exact selected retained-column RC2 path additionally admits Runtime's existing
Core 0.3.0 Base contract and binds responses and replay to the retained pack version.
Ordinary and manual paths retain 0.2.0-draft. This package does not expand Runtime's
conformance claim or approve external action.

For manual inputs and version 1 file mappings, evidence is a caller-declared map of requirement IDs to `present`, `absent`, or
`unknown`. It is not verified source acquisition. Omitted evidence is preserved as
Expand Down
19 changes: 16 additions & 3 deletions cmd/jpack-runner/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ func verifyRun(args []string, stdout, stderr io.Writer) error {
fmt.Fprintln(stderr, verificationCoverage)
flags.PrintDefaults()
}
conversionText := flags.String("conversion-contract", "", "optional: exact installed retained-column selector in canonical base64url")
file := flags.String("file", "", "retained verification export")
profilesPath := flags.String("profiles", "", "independently trusted input profiles JSON")
release := flags.String("release-digest", "", "independently trusted frozen release digest")
Expand All @@ -230,19 +231,31 @@ func verifyRun(args []string, stdout, stderr io.Writer) error {
}
// A version-3, 4 or 5 export may exceed 8 MiB by the record's bytes, the
// chain entry and the signature sidecar it carries.
raw, err := readLimit(*file, runner.MaxExportSize)
selection, err := runner.ParseConversionSelector(*conversionText, "preparation-verification")
if err != nil {
return err
}
p, err := readLimit(*profilesPath, 8<<20)
exportLimit, err := runner.ConversionExportLimit(selection)
if err != nil {
return err
}
raw, err := readLimit(*file, exportLimit)
if err != nil {
return err
}
profilesLimit := 8 << 20
if selection != nil {
profilesLimit = 80 << 10
}
p, err := readLimit(*profilesPath, profilesLimit)
if err != nil {
return err
}
profiles, err := runner.ParseInputProfiles(p)
if err != nil {
return err
}
verified, err := runner.VerifyInputs(raw, profiles, *release)
verified, err := runner.VerifyInputs(raw, profiles, *release, selection)
// A retained disposition that differs from the audit record is a finding
// beside the preparation's verification, which reads nothing of the
// disposition: when the preparation verified, its checked report is kept
Expand Down
24 changes: 18 additions & 6 deletions cmd/jpack-runner/verify_preparation.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ const preparationInputCap = 8<<20 + 1
// characters.
var sha256Form = regexp.MustCompile(`^sha256:[0-9a-f]{64}$`)

const verifyPreparationUsage = `Usage: jpack-runner verify-preparation --dialect FILE [--binding FILE] --case FILE --profiles FILE [--sources FILE] --preparation FILE --preparation-digest sha256:HEX
jpack-runner verify-preparation --unbound FILE --binding FILE --case FILE --profiles FILE [--sources FILE] --preparation FILE --preparation-digest sha256:HEX
const verifyPreparationUsage = `Usage: jpack-runner verify-preparation [--conversion-contract BASE64URL] --dialect FILE [--binding FILE] --case FILE --profiles FILE [--sources FILE] --preparation FILE --preparation-digest sha256:HEX
jpack-runner verify-preparation [--conversion-contract BASE64URL] --unbound FILE --binding FILE --case FILE --profiles FILE [--sources FILE] --preparation FILE --preparation-digest sha256:HEX
jpack-runner verify-preparation --capabilities

Verifies one preparation offline, as a preparation verifier of the specification's
Expand All @@ -46,7 +46,10 @@ It writes one report on standard output, one line, and the reason on standard er
and exits 0 for a reading, 1 for a refusal and 2 for a finding; 3, writing no report
and saying why on standard error, when it could not run: an argument it does not take,
a file it cannot open, a preparation its digest does not name, or -h. --capabilities
prints what it reads, as one JSON object, and exits 0.
prints interface and report capability version 2, including exact installed
retained-column support, as one JSON object, and exits 0. It takes no other flag.
Selected verification requires --conversion-contract explicitly; discovery does
not select an artifact, enlarge ordinary bounds or install any trusted identity.

A reading establishes that the preparation recomputes from these inputs. Its binding
is not-checked: no record is given, so nothing here commits the preparation or its
Expand All @@ -62,6 +65,7 @@ func verifyPreparation(args []string, stdout, stderr io.Writer) int {
fmt.Fprint(stderr, verifyPreparationUsage)
flags.PrintDefaults()
}
conversionText := flags.String("conversion-contract", "", "optional: exact installed retained-column selector in canonical base64url")
dialect := flags.String("dialect", "", "the dialect document: bound, or, with --binding, published with unbound sources, which the binding document binds as Runner's import step does (spec/dialect.md §4.4)")
unbound := flags.String("unbound", "", "the published dialect, with unbound sources, which --binding binds: --dialect with --binding, named so")
binding := flags.String("binding", "", "the binding document of a dialect with unbound sources")
Expand Down Expand Up @@ -109,7 +113,15 @@ func verifyPreparation(args []string, stdout, stderr io.Writer) int {
if given["unbound"] {
dialectPath = *unbound
}
fixture := runner.PreparationFixture{}
selection, err := runner.ParseConversionSelector(*conversionText, "document-validation", "preview", "preparation", "preparation-verification")
if err != nil {
return couldNot("%v", err)
}
fixture := runner.PreparationFixture{ConversionContract: selection}
inputCap := int64(preparationInputCap)
if selection != nil {
inputCap = 16<<20 + 1
}
for _, file := range []struct {
path string
into *[]byte
Expand All @@ -125,15 +137,15 @@ func verifyPreparation(args []string, stdout, stderr io.Writer) int {
if !file.given {
continue
}
b, err := readAtMost(file.path, preparationInputCap)
b, err := readAtMost(file.path, inputCap)
if err != nil {
return couldNot("%v", err)
}
*file.into = b
}
// The pin, before anything is read: a precondition, as a file the
// command can open is, and no reading of §11's (runner.PreparationPin).
if err := runner.PreparationPin(fixture.Preparation, *preparationDigest); err != nil {
if err := runner.PreparationPin(fixture.Preparation, *preparationDigest, selection); err != nil {
return couldNot("%v", err)
}
report := runner.VerifyPreparation(fixture)
Expand Down
38 changes: 23 additions & 15 deletions cmd/jpack-runner/verify_preparation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,9 +213,16 @@ func TestVerifyPreparationCapabilities(t *testing.T) {
t.Fatalf("%d %s %s", status, stdout, stderr)
}
report := reportOf(t, stdout)
if string(report["command"]) != `"verify-preparation"` || string(report["version"]) != "1" || string(report["dialectVersions"]) != "[2,3]" || string(report["sourceKinds"]) != `["operation","research"]` {
if string(report["command"]) != `"verify-preparation"` || string(report["version"]) != "2" || string(report["dialectVersions"]) != "[2,3]" || string(report["sourceKinds"]) != `["operation","research"]` {
t.Fatal(stdout)
}
var description struct {
Version int
Refusals []string
}
if err := json.Unmarshal(report["report"], &description); err != nil || description.Version != 2 || !strings.Contains(string(report["report"]), `"capability-unsupported"`) || !strings.Contains(string(report["report"]), `"profile-unsupported"`) || len(report["conversionContracts"]) == 0 {
t.Fatalf("selected version-2 discovery differs: %s", stdout)
}
}

// The expected preparation's digest is a precondition, as a file the command
Expand Down Expand Up @@ -251,20 +258,21 @@ func TestVerifyPreparationCouldNotRun(t *testing.T) {
}
rest := []string{"--case", dir + "case.json", "--profiles", dir + "profiles.json", "--sources", dir + "sources.json", "--preparation", dir + "preparation.json", "--preparation-digest", string(sum)}
for name, args := range map[string][]string{
"nothing": nil,
"help": {"-h"},
"a flag it does not take": append([]string{"--dialect", dir + "mapping.json", "--record", dir + "run.json"}, rest...),
"an argument": append([]string{"--dialect", dir + "mapping.json", "extra"}, rest...),
"both --dialect and --unbound": append([]string{"--dialect", dir + "mapping.json", "--unbound", dir + "unbound.json", "--binding", dir + "binding.json"}, rest...),
"--unbound without --binding": append([]string{"--unbound", dir + "unbound.json"}, rest...),
"no dialect": rest,
"no expected digest": append([]string{"--dialect", dir + "mapping.json"}, rest[:len(rest)-2]...),
"a digest of another form": append(append([]string{"--dialect", dir + "mapping.json"}, rest[:len(rest)-1]...), strings.ToUpper(string(sum))),
"a digest that does not name it": append(append([]string{"--dialect", dir + "mapping.json"}, rest[:len(rest)-1]...), "sha256:"+strings.Repeat("0", 64)),
"a file that is not there": append([]string{"--dialect", dir + "absent.json"}, rest...),
"a directory": append([]string{"--dialect", dir}, rest...),
"a flag naming no file": append([]string{"--dialect", dir + "mapping.json", "--binding", ""}, rest...),
"--capabilities with another flag": {"--capabilities", "--dialect", dir + "mapping.json"},
"nothing": nil,
"help": {"-h"},
"a flag it does not take": append([]string{"--dialect", dir + "mapping.json", "--record", dir + "run.json"}, rest...),
"an argument": append([]string{"--dialect", dir + "mapping.json", "extra"}, rest...),
"both --dialect and --unbound": append([]string{"--dialect", dir + "mapping.json", "--unbound", dir + "unbound.json", "--binding", dir + "binding.json"}, rest...),
"--unbound without --binding": append([]string{"--unbound", dir + "unbound.json"}, rest...),
"no dialect": rest,
"no expected digest": append([]string{"--dialect", dir + "mapping.json"}, rest[:len(rest)-2]...),
"a digest of another form": append(append([]string{"--dialect", dir + "mapping.json"}, rest[:len(rest)-1]...), strings.ToUpper(string(sum))),
"a digest that does not name it": append(append([]string{"--dialect", dir + "mapping.json"}, rest[:len(rest)-1]...), "sha256:"+strings.Repeat("0", 64)),
"a file that is not there": append([]string{"--dialect", dir + "absent.json"}, rest...),
"a directory": append([]string{"--dialect", dir}, rest...),
"a flag naming no file": append([]string{"--dialect", dir + "mapping.json", "--binding", ""}, rest...),
"--capabilities with another flag": {"--capabilities", "--dialect", dir + "mapping.json"},
"--capabilities with conversion selection": {"--capabilities", "--conversion-contract", "not-an-admitted-selector"},
} {
t.Run(name, func(t *testing.T) {
status, stdout, stderr := runVerifyPreparation(args...)
Expand Down
21 changes: 19 additions & 2 deletions docs/MAPPING-V2.md
Original file line number Diff line number Diff line change
Expand Up @@ -1911,7 +1911,9 @@ It writes §11's report on standard output, one line in that canonical form,
and why on standard error, and exits 0 for a reading, 1 for a refusal and 2 for
a finding; 3, with no report, when it could not run: an argument it does not
take, a file it cannot open, a preparation its digest does not name, `-h`. Its
refusals are §11's and no other. A refusal is exactly
ordinary refusals are §11's. Explicit retained-column selection additionally
names unsupported selection/profile refusals in its version-2 capability
description below. A refusal's JSON form is exactly
`{"refusal":"input-malformed","result":"refusal"}` and a finding
`{"finding":"acquisition-invalid","result":"finding"}`. A reading is exactly
`result`, `digest`, `binding`, `facts`, `evidence`, `targetsByClass`, and
Expand All @@ -1929,13 +1931,28 @@ does, for a run's export.

`jpack-runner verify-preparation --capabilities` prints, alone, one closed
object for a caller to check before it calls: the command's version
(`"version":1`), the release it was built from (`runner`), the dialect versions
(`"version":2`), the release it was built from (`runner`), the dialect versions
(`[2,3]`) and named formats (`"2.0.0"`, `"3.0.0"`), the source kinds and shapes
it reads, the instant it recomputes at, its report's form, results, binding,
refusal and finding codes and exit statuses, its preconditions
(`"preconditions":["preparation-digest"]`, each `couldNotRun` when it fails),
and the bounds it holds the documents to.

Interface version 2 adds the explicit `--conversion-contract BASE64URL` flag and
`conversionContracts`, the exact installed retained-column Base declaration.
`--capabilities` still takes no other flag, including a conversion selector.
Discovery describes support; it neither selects an artifact nor changes the
ordinary bounds. Selected verification uses the explicit selector before files
are opened, as [the selected contract](design/retained-columns-draft.md) describes.

The nested report capability description is also version 2: its declared refusal
vocabulary additionally names `capability-unsupported` and `profile-unsupported`
for the retained-column extension. This does not add members to the actual §11
reading, refusal or finding JSON and does not change exit statuses. Ordinary
preparations retain canonical recomputation: unrelated extra preparation members
are a `preparation-differs` finding, while a missing, altered or malformed retained
conversion selector refuses instead of silently changing explicit context.

**What a reading establishes, and what it does not** (§13, §14). A reading
establishes that the preparation, byte for byte in the canonical form,
recomputes from the files given at the instant it names: that the derivations
Expand Down
Loading
Loading