From 2b889b7df0f7b958a87a29df241f7b2cab11533a Mon Sep 17 00:00:00 2001 From: Tatsat Mishra Date: Sun, 2 Aug 2026 15:50:55 +1200 Subject: [PATCH 1/6] docs: add architecture overview and golangci-lint tooling Add ARCHITECTURE.md documenting the codebase map, package layout, core sign/verify workflows, trust model, and developer workflow, linked from README.md and building.md. Add golangci-lint tooling: a conservative .golangci.yml adopted incrementally via new-from-rev, a 'lint' Makefile target, and a CI lint step (with fetch-depth: 0 so new-from-rev gating has git history). Signed-off-by: Tatsat Mishra --- .github/workflows/build.yml | 7 + .golangci.yml | 52 ++++++ ARCHITECTURE.md | 311 ++++++++++++++++++++++++++++++++++++ Makefile | 4 + README.md | 1 + building.md | 2 + 6 files changed, 377 insertions(+) create mode 100644 .golangci.yml create mode 100644 ARCHITECTURE.md diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0062fa638..7b7958fa3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -43,6 +43,9 @@ jobs: check-latest: true - name: Check out code uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + # Full history is required for golangci-lint's `new-from-rev` gating. + fetch-depth: 0 - name: Cache Go modules uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 id: go-mod-cache @@ -53,6 +56,10 @@ jobs: ${{ runner.os }}-go- - name: Get dependencies run: make download + - name: Lint + uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0 + with: + version: v2.5.0 - name: Build run: make build - name: Run unit tests diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 000000000..0910f9a59 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,52 @@ +# Copyright The Notary Project Authors. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +version: "2" + +run: + timeout: 5m + +# Adopt linting incrementally: only fail on issues introduced by new commits, +# not on the pre-existing backlog. Remove `new-from-rev` once the backlog under +# `make lint` is cleared to enforce linting across the whole tree. +issues: + new-from-rev: HEAD + max-issues-per-linter: 0 + max-same-issues: 0 + +linters: + # Start conservative: the default set plus a few high-signal linters. + # Expand this list over time as the codebase is cleaned up. + default: standard + enable: + - bodyclose + - misspell + - revive + - unconvert + - whitespace + exclusions: + generated: lax + presets: + - comments + - std-error-handling + paths: + - test/e2e + +formatters: + enable: + - gofmt + - goimports + settings: + goimports: + local-prefixes: + - github.com/notaryproject/notation diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 000000000..1c6f5e004 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,311 @@ +# Notation Architecture + +Notation is the [Notary Project](https://notaryproject.dev) CLI for signing and +verifying artifacts in the OCI registry ecosystem. It stores signatures as OCI +**referrers** alongside the artifact they sign — conceptually similar to git +commit signing, but generic and usable for arbitrary security purposes. + +- **Module:** `github.com/notaryproject/notation/v2` (Go `>= 1.24`) +- **Entry point:** [`cmd/notation/main.go`](cmd/notation/main.go) → `run()` assembles the root Cobra command and registers all subcommands +- **Core frameworks:** [Cobra](https://github.com/spf13/cobra) (CLI), [`oras-go/v2`](https://oras.land) (OCI registry & OCI-layout I/O) +- **Notary libraries** (where the real work happens): + - `notation-go` — sign / verify / list algorithms, trust policy, plugin manager + - `notation-core-go` — signature envelopes, X.509, revocation (CRL/OCSP) + - `notation-plugin-framework-go` — plugin contract + - `tspclient-go` — RFC 3161 timestamping + +## Table of Contents + +- [Design Philosophy](#design-philosophy) +- [High-Level Architecture](#high-level-architecture) +- [Package Layout](#package-layout) +- [Core Workflows](#core-workflows) +- [Trust Model](#trust-model) +- [Developer Workflow](#developer-workflow) +- [User-Facing CLI Workflows](#user-facing-cli-workflows) +- [Improvement Opportunities](#improvement-opportunities) + +## Design Philosophy + +1. **Thin CLI layer.** Command files in `cmd/notation/` only parse flags and + orchestrate. All cryptographic algorithms live in `notation-go` / + `notation-core-go`. This keeps the CLI auditable and lets the libraries be + reused by other tools. +2. **Centralized registry plumbing.** All OCI registry, auth, and OCI-layout + access flows through [`registry.go`](cmd/notation/registry.go) + (`getRepository`), so transport, credentials, and referrers-fallback logic + live in one place. +3. **Two `internal/` trees, two concerns.** + - `cmd/notation/internal/` — CLI *presentation* concerns (flags, output + rendering, signer/verifier construction, experimental gating). + - `internal/` — reusable *lower-level* utilities (auth store, config cache, + HTTP client, revocation, x509, version). +4. **Pluggable everything.** Signing keys, verification, and revocation are all + pluggable via the plugin framework and JSON trust policies. + +## High-Level Architecture + +``` +┌─────────────────────────────────────────────────────────────┐ +│ CLI Layer (cmd/notation/*.go — Cobra commands) │ +│ sign · verify · list · inspect · login/logout · key │ +│ subcommands: blob/ · cert/ · plugin/ · policy/ │ +└───────────────┬─────────────────────────────────────────────┘ + │ delegates to +┌───────────────▼─────────────────────────────────────────────┐ +│ CLI-internal (cmd/notation/internal/) │ +│ flag · display · sign(GetSigner) · verify(GetVerifier) │ +│ truststore · experimental · errors · plugin │ +└───────────────┬─────────────────────────────────────────────┘ + │ uses +┌───────────────▼──────────────┐ ┌──────────────────────────┐ +│ Shared utils (internal/) │ │ External Notary libs │ +│ auth · config · envelope │ │ notation-go (sign/vfy) │ +│ httputil · revocation · x509│ │ notation-core-go (crypto)│ +│ osutil · trace · version │ │ oras-go (registry) │ +└──────────────────────────────┘ └──────────────────────────┘ +``` + +## Package Layout + +### `cmd/notation/` — Top-Level Commands + +| File | Purpose | +|------|---------| +| `sign.go` | Signs an OCI artifact. Resolves a signer, builds `SignOptions`, calls `notation.SignOCI`, pushes signature as a referrer. | +| `verify.go` | Verifies signatures on an OCI artifact via `notation.Verify` and renders results. | +| `list.go` | Lists all signatures for an artifact (`ListSignatures`), rendered as a tree. | +| `inspect.go` | Decodes each signature envelope and renders as tree or JSON. | +| `login.go` / `logout.go` | Registry credential management via oras `credentials`. | +| `key.go` | Manages the signing-key list in `config.json` (`key add/update/delete/list`). | +| `registry.go` | **Not a command** — OCI registry plumbing (`getRepository`, auth client, referrers fallback). | +| `manifest.go` | **Not a command** — reference resolution (tag→digest), mutable-tag warnings. | +| `version.go` | Prints version, Go version, OS/arch, git commit. | + +### `cmd/notation/` — Subcommand Packages + +- **`blob/`** — detached-signature workflow for arbitrary files (`sign`, `verify`, `inspect`) plus `blob/policy/` for blob trust-policy management. +- **`cert/`** — trust-store certificate management (`add`, `list`, `show`, `delete`, `generate-test`, `cleanup-test`). +- **`plugin/`** — plugin lifecycle (`list`, `install` from file/URL, `uninstall`). +- **`policy/`** — OCI trust-policy management (`import`, `show`). + +### `cmd/notation/internal/` — CLI Presentation + +| Package | Purpose | +|---------|---------| +| `flag/` | Shared flag option structs (signer, logging, secure/credentials, output format). | +| `display/` | Output-handler factory + `metadata/` renderers (json/text/tree) and `output/` printer. | +| `sign/` | `GetSigner` — resolves a local X.509 key pair or a plugin signer. | +| `verify/` | `GetVerifier`/`GetBlobVerifier` — builds a verifier with trust policy, trust store, revocation, plugins; composes failure messages. | +| `truststore/` | Trust-store filesystem operations and validation. | +| `experimental/` | Gates experimental features behind `NOTATION_EXPERIMENTAL=1`. | +| `errors/` | Typed CLI errors (referrers-API unsupported, missing reference, max signatures). | +| `plugin/` | Plugin source handling (file vs URL), download-size limits, media types. | + +### `internal/` — Shared Utilities + +| Package | Purpose | +|---------|---------| +| `auth/` | Builds an oras credentials store (Notation → Docker → OS-native). | +| `config/` | Cached read of `config.json`; `IsRegistryInsecure` helper. | +| `envelope/` | Signature envelope constants (COSE/JWS) and payload wrapping. | +| `httputil/` | oras `auth.Client`/`http.Client` with retry, debug logging, user agent. | +| `revocation/` | CRL/OCSP revocation validators with on-disk CRL cache (`crl/`). | +| `x509/` | X.509 helpers (root cert detection, cert pools for TSA roots). | +| `osutil/` | File utilities (SHA-256, size-limited writes/downloads). | +| `slices/` | Generic `Contains` helper. | +| `trace/` | HTTP debug-logging transport and logger-level context. | +| `version/` | Version constants (`Version`, `BuildMetadata`, `GitCommit`) injected at build time. | + +### Supporting Directories + +- **`specs/`** — design docs and per-command specifications, plus `proposals/` (blob signing, diagnostic experience, dm-verity). +- **`test/e2e/`** — a separate Go module of Ginkgo end-to-end tests, plus a mock plugin module. + +## Core Workflows + +### Signing (`runSign`, `cmd/notation/sign.go`) + +``` +sign.GetSigner ──► notation-go signer (local key pair OR plugin signer) + │ +getRepository ──► oras OCI repository (remote registry or OCI layout) + │ +prepareSigningOpts ──► notation.SignOptions + │ (envelope media type, expiry, plugin config, + │ user metadata, optional TSA timestamper + revocation) + │ +resolveReference ──► tag resolved to immutable digest + │ +notation.SignOCI(ctx, signer, sigRepo, opts) + └──► notation-go signs and PUSHES the signature to the registry + as an OCI referrer of the target artifact. +``` + +### Verification (`runVerify`, `cmd/notation/verify.go`) + +``` +verify.GetVerifier ──► verifier with: + │ • X.509 trust store + │ • OCI trust policy (trustpolicy.LoadOCIDocument) + │ • revocation validators (CRL/OCSP) + │ • plugin manager + │ +getRepository + resolveReference + │ +notation.Verify(ctx, sigVerifier, sigRepo, opts) + │ +ComposeVerificationFailurePrintout (on failure) + │ +display handler renders result (tree / json / text) +``` + +Blob commands mirror these flows using `notation.BlobSigner` / `BlobVerifier`. + +## Trust Model + +Verification is governed by three on-disk artifacts, all under the Notation +config directory (overridable with `NOTATION_CONFIG`): + +1. **Trust store** — X.509 CA/certificate roots under + `truststore/x509///`, managed by `notation cert`. +2. **Trust policy** — a JSON document (`trustpolicy.oci.json` / + `trustpolicy.blob.json`) mapping registry scopes to trust stores, signature + verification levels, and trusted identities; managed by `notation policy` / + `notation blob policy`. +3. **Signing keys** — the key list in `config.json`, managed by `notation key`. + +Revocation (CRL/OCSP) and RFC 3161 timestamping are layered on top during both +signing and verification. + +## Developer Workflow + +Build tooling is driven by the [`Makefile`](Makefile). Key targets: + +| Command | Description | +|---------|-------------| +| `make build` | Builds `bin/notation` with version info injected via `-ldflags`. | +| `make install` | Builds and copies `notation` to `~/bin/`. | +| `make test` | Runs unit tests with race detector and coverage (`coverage.txt`). | +| `make lint` | Runs `golangci-lint` using `.golangci.yml` (adopted incrementally via `new-from-rev`). | +| `make e2e` | Builds the CLI and runs the Ginkgo e2e suite against a `zot` registry. | +| `make e2e-covdata` | Runs e2e with binary coverage instrumentation. | +| `make download` | Downloads Go module dependencies. | +| `make vendor` | Vendors Go modules. | +| `make check-line-endings` / `fix-line-endings` | Enforces LF line endings on `.go` files. | + +Version metadata (`GitCommit`, `BuildMetadata`) is injected at link time from +git state — see the `LDFLAGS` block in the Makefile. + +### CI/CD Pipeline (`.github/workflows/`) + +``` + push / pull_request + │ + build.yml (Continuous Integration) + ├── check signed commits (PRs must be signed) + ├── setup Go 1.24 + module cache + ├── make download → make build + ├── golangci-lint (new-issue gating) + ├── make test (unit, race, coverage) + ├── make e2e-covdata (e2e against zot) + └── upload coverage → codecov.io + + push tag v* + │ + release-github.yml + └── GoReleaser (v2) → GitHub release with cross-platform binaries +``` + +Additional workflows: `codeql.yml` (SAST), `scorecard.yml` (OpenSSF), +`license-checker.yml`, `stale.yml`, `add-to-project.yml`. Dependencies are kept +current by `dependabot.yml`. All commits must be **signed**. + +## User-Facing CLI Workflows + +### Sign & verify an image (registry) + +```sh +# 1. Authenticate to the registry +notation login registry.example.com + +# 2. Register a signing key (or use a plugin/KMS key) +notation cert generate-test --default "example.com" + +# 3. Sign the artifact (signature stored as an OCI referrer) +notation sign registry.example.com/app:v1 + +# 4. Configure a trust policy and verify +notation policy import ./trustpolicy.json +notation verify registry.example.com/app:v1 + +# 5. Inspect / list signatures +notation list registry.example.com/app:v1 +notation inspect registry.example.com/app:v1 +``` + +### Detached blob signing + +```sh +notation blob policy import ./trustpolicy.blob.json +notation blob sign ./artifact.tar.gz # emits a detached .sig +notation blob verify --signature artifact.tar.gz.sig ./artifact.tar.gz +``` + +### Plugin / KMS-backed signing + +```sh +notation plugin install --file ./notation-myplugin.tar.gz +notation key add --plugin myplugin --id mykey +notation sign --key mykey registry.example.com/app:v1 +``` + +## Improvement Opportunities + +The following are suggestions, not existing commitments. They are ordered by +approximate value-to-effort. + +### Documentation & onboarding +- **This document** — keep `ARCHITECTURE.md` linked from `README.md` and + `building.md` so new contributors have a map of the codebase. +- Add a short **"first contribution" walkthrough** (build → run a unit test → + run one e2e case) to `building.md`; currently it only covers `make install`. + +### Developer workflow / CI +- **Split CI jobs** — unit and e2e run in one job; separating them (with e2e as + a matrix over registry backends) improves signal and parallelism. +- **Cache e2e registry images** to reduce flakiness and runtime. +- **Burn down the lint backlog.** `make lint` is adopted incrementally + (`new-from-rev` in `.golangci.yml`) so only new issues fail CI. Roughly ~76 + pre-existing findings remain; clearing them lets `new-from-rev` be removed to + enforce linting across the whole tree. +- **Pin and document the Go toolchain** via a `go.work`/toolchain directive so + local and CI builds are reproducible. + +### Codebase / architecture +- **Consolidate reference-resolution logic.** `registry.go` and `manifest.go` + both handle registry-vs-OCI-layout branching; a single `target resolver` + abstraction would reduce duplication across `sign`/`verify`/`list`/`inspect`. +- **Unify OCI and blob flows.** Signing/verification exist in near-parallel OCI + and blob variants; extracting a shared orchestration interface (signer + + target + options) would cut duplicated flag/plumbing code. +- **Structured error taxonomy.** Extend `cmd/notation/internal/errors` into a + consistent, exit-code-mapped error hierarchy so scripts can reliably branch on + failure classes (network vs. policy vs. crypto). +- **Machine-readable output everywhere.** `--output json` is available on some + commands (inspect/verify); making it uniform across `list`, `sign`, and `key` + would improve scriptability and CI integration. + +### User experience +- **Progress + diagnostics.** A consistent `--debug`/verbosity story (already + partly present via `trace/`) surfaced uniformly across commands aids + troubleshooting of registry/auth failures. +- **`notation doctor`** — a diagnostic command that validates config directory, + trust policy syntax, trust-store contents, and registry connectivity in one + shot would shorten support loops. + +--- + +*This document reflects the repository state at the time of writing. When +command wiring in `cmd/notation/main.go` or the package layout changes, update +the corresponding sections here.* diff --git a/Makefile b/Makefile index a2e8fe596..27fe65d18 100644 --- a/Makefile +++ b/Makefile @@ -71,6 +71,10 @@ e2e-covdata: export GO_INSTRUMENT_FLAGS='-coverpkg "github.com/notaryproject/notation/v2/internal/...,github.com/notaryproject/notation/v2/cmd/..."'; \ $(MAKE) e2e && go tool covdata textfmt -i=$$GOCOVERDIR -o "$(CURDIR)/test/e2e/coverage.txt" +.PHONY: lint +lint: ## run golangci-lint (install: https://golangci-lint.run/welcome/install/) + golangci-lint run + .PHONY: clean clean: git status --ignored --short | grep '^!! ' | sed 's/!! //' | xargs rm -rf diff --git a/README.md b/README.md index 68a86b4be..d628b9285 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ Notary Project is a [CNCF Incubating project](https://www.cncf.io/projects/notar ### Development and Contributing +- [Architecture overview](/ARCHITECTURE.md) - [Build Notation from source code](/building.md) - [Governance for Notary Project](https://github.com/notaryproject/.github/blob/master/GOVERNANCE.md) - [Maintainers and reviewers list](https://github.com/notaryproject/notation/blob/main/CODEOWNERS) diff --git a/building.md b/building.md index 4e03d271d..f7648606b 100644 --- a/building.md +++ b/building.md @@ -6,6 +6,8 @@ The notation repo contains the following: Building above binaries require [golang](https://golang.org/dl/) with version `>= 1.24`. +> For a map of the codebase and how the CLI is structured, see [ARCHITECTURE.md](/ARCHITECTURE.md). + ## Windows with WSL or Linux - Build the binaries, installing them to: From 9a053f437db7807c2ae1fd21e530093204fdd8a3 Mon Sep 17 00:00:00 2001 From: Tatsat Mishra Date: Sun, 2 Aug 2026 16:01:08 +1200 Subject: [PATCH 2/6] fix: use merge-base gating for incremental golangci-lint new-from-rev: HEAD compares the tree against itself, producing an empty diff so no PR-introduced issues are ever reported. Switch to new-from-merge-base: origin/main so lint issues introduced by a PR are caught while the pre-existing backlog stays unenforced. Update the build.yml checkout comment and ARCHITECTURE.md to match. Signed-off-by: Tatsat Mishra --- .github/workflows/build.yml | 3 ++- .golangci.yml | 9 +++++---- ARCHITECTURE.md | 6 +++--- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7b7958fa3..413395449 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -44,7 +44,8 @@ jobs: - name: Check out code uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: - # Full history is required for golangci-lint's `new-from-rev` gating. + # Full history is required for golangci-lint's merge-base + # (new-issues) gating to diff a PR against the default branch. fetch-depth: 0 - name: Cache Go modules uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 diff --git a/.golangci.yml b/.golangci.yml index 0910f9a59..b1568d5c6 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -16,11 +16,12 @@ version: "2" run: timeout: 5m -# Adopt linting incrementally: only fail on issues introduced by new commits, -# not on the pre-existing backlog. Remove `new-from-rev` once the backlog under -# `make lint` is cleared to enforce linting across the whole tree. +# Adopt linting incrementally: only fail on issues introduced by a PR relative +# to its merge base with the default branch, not on the pre-existing backlog. +# Remove `new-from-merge-base` once the backlog under `make lint` is cleared to +# enforce linting across the whole tree. issues: - new-from-rev: HEAD + new-from-merge-base: origin/main max-issues-per-linter: 0 max-same-issues: 0 diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 1c6f5e004..cd067e153 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -187,7 +187,7 @@ Build tooling is driven by the [`Makefile`](Makefile). Key targets: | `make build` | Builds `bin/notation` with version info injected via `-ldflags`. | | `make install` | Builds and copies `notation` to `~/bin/`. | | `make test` | Runs unit tests with race detector and coverage (`coverage.txt`). | -| `make lint` | Runs `golangci-lint` using `.golangci.yml` (adopted incrementally via `new-from-rev`). | +| `make lint` | Runs `golangci-lint` using `.golangci.yml` (adopted incrementally via `new-from-merge-base`). | | `make e2e` | Builds the CLI and runs the Ginkgo e2e suite against a `zot` registry. | | `make e2e-covdata` | Runs e2e with binary coverage instrumentation. | | `make download` | Downloads Go module dependencies. | @@ -276,8 +276,8 @@ approximate value-to-effort. a matrix over registry backends) improves signal and parallelism. - **Cache e2e registry images** to reduce flakiness and runtime. - **Burn down the lint backlog.** `make lint` is adopted incrementally - (`new-from-rev` in `.golangci.yml`) so only new issues fail CI. Roughly ~76 - pre-existing findings remain; clearing them lets `new-from-rev` be removed to + (`new-from-merge-base` in `.golangci.yml`) so only new issues fail CI. Roughly ~76 + pre-existing findings remain; clearing them lets `new-from-merge-base` be removed to enforce linting across the whole tree. - **Pin and document the Go toolchain** via a `go.work`/toolchain directive so local and CI builds are reproducible. From 6b03b3f09a5fd857554900dc7e5da624bcc0c7dd Mon Sep 17 00:00:00 2001 From: Tatsat Mishra Date: Mon, 3 Aug 2026 14:31:06 +1200 Subject: [PATCH 3/6] docs: address review feedback on ARCHITECTURE.md - Remove package-layout tables; defer symbol-level detail to godoc. - Convert ASCII diagrams to mermaid (high-level, sign/verify, CI/CD). - Remove hard line-wrapping in prose per markdown preference. - Remove the Improvement Opportunities section; such items belong in roadmaps/issues rather than architecture docs. Signed-off-by: Tatsat Mishra --- ARCHITECTURE.md | 253 ++++++++++-------------------------------------- 1 file changed, 53 insertions(+), 200 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index cd067e153..5772a7db2 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -1,9 +1,6 @@ # Notation Architecture -Notation is the [Notary Project](https://notaryproject.dev) CLI for signing and -verifying artifacts in the OCI registry ecosystem. It stores signatures as OCI -**referrers** alongside the artifact they sign — conceptually similar to git -commit signing, but generic and usable for arbitrary security purposes. +Notation is the [Notary Project](https://notaryproject.dev) CLI for signing and verifying artifacts in the OCI registry ecosystem. It stores signatures as OCI **referrers** alongside the artifact they sign — conceptually similar to git commit signing, but generic and usable for arbitrary security purposes. - **Module:** `github.com/notaryproject/notation/v2` (Go `>= 1.24`) - **Entry point:** [`cmd/notation/main.go`](cmd/notation/main.go) → `run()` assembles the root Cobra command and registers all subcommands @@ -14,169 +11,81 @@ commit signing, but generic and usable for arbitrary security purposes. - `notation-plugin-framework-go` — plugin contract - `tspclient-go` — RFC 3161 timestamping +For package- and symbol-level detail, see the Go documentation (`go doc ./...` or [pkg.go.dev](https://pkg.go.dev/github.com/notaryproject/notation/v2)); this document intentionally stays at the architectural level so it does not drift from the code. + ## Table of Contents - [Design Philosophy](#design-philosophy) - [High-Level Architecture](#high-level-architecture) -- [Package Layout](#package-layout) - [Core Workflows](#core-workflows) - [Trust Model](#trust-model) - [Developer Workflow](#developer-workflow) - [User-Facing CLI Workflows](#user-facing-cli-workflows) -- [Improvement Opportunities](#improvement-opportunities) ## Design Philosophy -1. **Thin CLI layer.** Command files in `cmd/notation/` only parse flags and - orchestrate. All cryptographic algorithms live in `notation-go` / - `notation-core-go`. This keeps the CLI auditable and lets the libraries be - reused by other tools. -2. **Centralized registry plumbing.** All OCI registry, auth, and OCI-layout - access flows through [`registry.go`](cmd/notation/registry.go) - (`getRepository`), so transport, credentials, and referrers-fallback logic - live in one place. +1. **Thin CLI layer.** Command files in `cmd/notation/` only parse flags and orchestrate. All cryptographic algorithms live in `notation-go` / `notation-core-go`. This keeps the CLI auditable and lets the libraries be reused by other tools. +2. **Centralized registry plumbing.** All OCI registry, auth, and OCI-layout access flows through [`registry.go`](cmd/notation/registry.go) (`getRepository`), so transport, credentials, and referrers-fallback logic live in one place. 3. **Two `internal/` trees, two concerns.** - - `cmd/notation/internal/` — CLI *presentation* concerns (flags, output - rendering, signer/verifier construction, experimental gating). - - `internal/` — reusable *lower-level* utilities (auth store, config cache, - HTTP client, revocation, x509, version). -4. **Pluggable everything.** Signing keys, verification, and revocation are all - pluggable via the plugin framework and JSON trust policies. + - `cmd/notation/internal/` — CLI *presentation* concerns (flags, output rendering, signer/verifier construction, experimental gating). + - `internal/` — reusable *lower-level* utilities (auth store, config cache, HTTP client, revocation, x509, version). +4. **Pluggable everything.** Signing keys, verification, and revocation are all pluggable via the plugin framework and JSON trust policies. ## High-Level Architecture -``` -┌─────────────────────────────────────────────────────────────┐ -│ CLI Layer (cmd/notation/*.go — Cobra commands) │ -│ sign · verify · list · inspect · login/logout · key │ -│ subcommands: blob/ · cert/ · plugin/ · policy/ │ -└───────────────┬─────────────────────────────────────────────┘ - │ delegates to -┌───────────────▼─────────────────────────────────────────────┐ -│ CLI-internal (cmd/notation/internal/) │ -│ flag · display · sign(GetSigner) · verify(GetVerifier) │ -│ truststore · experimental · errors · plugin │ -└───────────────┬─────────────────────────────────────────────┘ - │ uses -┌───────────────▼──────────────┐ ┌──────────────────────────┐ -│ Shared utils (internal/) │ │ External Notary libs │ -│ auth · config · envelope │ │ notation-go (sign/vfy) │ -│ httputil · revocation · x509│ │ notation-core-go (crypto)│ -│ osutil · trace · version │ │ oras-go (registry) │ -└──────────────────────────────┘ └──────────────────────────┘ +```mermaid +flowchart TD + CLI["CLI Layer — cmd/notation/*.go (Cobra commands)
sign · verify · list · inspect · login/logout · key
subcommands: blob/ · cert/ · plugin/ · policy/"] + Internal["CLI-internal — cmd/notation/internal/
flag · display · sign (GetSigner) · verify (GetVerifier)
truststore · experimental · errors · plugin"] + Utils["Shared utils — internal/
auth · config · envelope · httputil
revocation · x509 · osutil · trace · version"] + Libs["External Notary libs
notation-go (sign/verify)
notation-core-go (crypto)
oras-go (registry)"] + + CLI -->|delegates to| Internal + Internal -->|uses| Utils + Internal -->|uses| Libs ``` -## Package Layout - -### `cmd/notation/` — Top-Level Commands - -| File | Purpose | -|------|---------| -| `sign.go` | Signs an OCI artifact. Resolves a signer, builds `SignOptions`, calls `notation.SignOCI`, pushes signature as a referrer. | -| `verify.go` | Verifies signatures on an OCI artifact via `notation.Verify` and renders results. | -| `list.go` | Lists all signatures for an artifact (`ListSignatures`), rendered as a tree. | -| `inspect.go` | Decodes each signature envelope and renders as tree or JSON. | -| `login.go` / `logout.go` | Registry credential management via oras `credentials`. | -| `key.go` | Manages the signing-key list in `config.json` (`key add/update/delete/list`). | -| `registry.go` | **Not a command** — OCI registry plumbing (`getRepository`, auth client, referrers fallback). | -| `manifest.go` | **Not a command** — reference resolution (tag→digest), mutable-tag warnings. | -| `version.go` | Prints version, Go version, OS/arch, git commit. | - -### `cmd/notation/` — Subcommand Packages - -- **`blob/`** — detached-signature workflow for arbitrary files (`sign`, `verify`, `inspect`) plus `blob/policy/` for blob trust-policy management. -- **`cert/`** — trust-store certificate management (`add`, `list`, `show`, `delete`, `generate-test`, `cleanup-test`). -- **`plugin/`** — plugin lifecycle (`list`, `install` from file/URL, `uninstall`). -- **`policy/`** — OCI trust-policy management (`import`, `show`). - -### `cmd/notation/internal/` — CLI Presentation - -| Package | Purpose | -|---------|---------| -| `flag/` | Shared flag option structs (signer, logging, secure/credentials, output format). | -| `display/` | Output-handler factory + `metadata/` renderers (json/text/tree) and `output/` printer. | -| `sign/` | `GetSigner` — resolves a local X.509 key pair or a plugin signer. | -| `verify/` | `GetVerifier`/`GetBlobVerifier` — builds a verifier with trust policy, trust store, revocation, plugins; composes failure messages. | -| `truststore/` | Trust-store filesystem operations and validation. | -| `experimental/` | Gates experimental features behind `NOTATION_EXPERIMENTAL=1`. | -| `errors/` | Typed CLI errors (referrers-API unsupported, missing reference, max signatures). | -| `plugin/` | Plugin source handling (file vs URL), download-size limits, media types. | - -### `internal/` — Shared Utilities - -| Package | Purpose | -|---------|---------| -| `auth/` | Builds an oras credentials store (Notation → Docker → OS-native). | -| `config/` | Cached read of `config.json`; `IsRegistryInsecure` helper. | -| `envelope/` | Signature envelope constants (COSE/JWS) and payload wrapping. | -| `httputil/` | oras `auth.Client`/`http.Client` with retry, debug logging, user agent. | -| `revocation/` | CRL/OCSP revocation validators with on-disk CRL cache (`crl/`). | -| `x509/` | X.509 helpers (root cert detection, cert pools for TSA roots). | -| `osutil/` | File utilities (SHA-256, size-limited writes/downloads). | -| `slices/` | Generic `Contains` helper. | -| `trace/` | HTTP debug-logging transport and logger-level context. | -| `version/` | Version constants (`Version`, `BuildMetadata`, `GitCommit`) injected at build time. | - -### Supporting Directories - -- **`specs/`** — design docs and per-command specifications, plus `proposals/` (blob signing, diagnostic experience, dm-verity). -- **`test/e2e/`** — a separate Go module of Ginkgo end-to-end tests, plus a mock plugin module. +The package layout under these trees is documented in the Go source itself; run `go doc ./cmd/notation/...` or `go doc ./internal/...` for the authoritative, always-current listing. ## Core Workflows ### Signing (`runSign`, `cmd/notation/sign.go`) -``` -sign.GetSigner ──► notation-go signer (local key pair OR plugin signer) - │ -getRepository ──► oras OCI repository (remote registry or OCI layout) - │ -prepareSigningOpts ──► notation.SignOptions - │ (envelope media type, expiry, plugin config, - │ user metadata, optional TSA timestamper + revocation) - │ -resolveReference ──► tag resolved to immutable digest - │ -notation.SignOCI(ctx, signer, sigRepo, opts) - └──► notation-go signs and PUSHES the signature to the registry - as an OCI referrer of the target artifact. +```mermaid +flowchart TD + A["sign.GetSigner
notation-go signer (local key pair OR plugin signer)"] + B["getRepository
oras OCI repository (remote registry or OCI layout)"] + C["prepareSigningOpts → notation.SignOptions
(envelope media type, expiry, plugin config,
user metadata, optional TSA timestamper + revocation)"] + D["resolveReference
tag resolved to immutable digest"] + E["notation.SignOCI(ctx, signer, sigRepo, opts)
notation-go signs and PUSHES the signature to the
registry as an OCI referrer of the target artifact"] + + A --> B --> C --> D --> E ``` ### Verification (`runVerify`, `cmd/notation/verify.go`) -``` -verify.GetVerifier ──► verifier with: - │ • X.509 trust store - │ • OCI trust policy (trustpolicy.LoadOCIDocument) - │ • revocation validators (CRL/OCSP) - │ • plugin manager - │ -getRepository + resolveReference - │ -notation.Verify(ctx, sigVerifier, sigRepo, opts) - │ -ComposeVerificationFailurePrintout (on failure) - │ -display handler renders result (tree / json / text) +```mermaid +flowchart TD + A["verify.GetVerifier
verifier with X.509 trust store, OCI trust policy
(trustpolicy.LoadOCIDocument), revocation validators
(CRL/OCSP), plugin manager"] + B["getRepository + resolveReference"] + C["notation.Verify(ctx, sigVerifier, sigRepo, opts)"] + D["ComposeVerificationFailurePrintout (on failure)"] + E["display handler renders result (tree / json / text)"] + + A --> B --> C --> D --> E ``` Blob commands mirror these flows using `notation.BlobSigner` / `BlobVerifier`. ## Trust Model -Verification is governed by three on-disk artifacts, all under the Notation -config directory (overridable with `NOTATION_CONFIG`): +Verification is governed by three on-disk artifacts, all under the Notation config directory (overridable with `NOTATION_CONFIG`): -1. **Trust store** — X.509 CA/certificate roots under - `truststore/x509///`, managed by `notation cert`. -2. **Trust policy** — a JSON document (`trustpolicy.oci.json` / - `trustpolicy.blob.json`) mapping registry scopes to trust stores, signature - verification levels, and trusted identities; managed by `notation policy` / - `notation blob policy`. +1. **Trust store** — X.509 CA/certificate roots under `truststore/x509///`, managed by `notation cert`. +2. **Trust policy** — a JSON document (`trustpolicy.oci.json` / `trustpolicy.blob.json`) mapping registry scopes to trust stores, signature verification levels, and trusted identities; managed by `notation policy` / `notation blob policy`. 3. **Signing keys** — the key list in `config.json`, managed by `notation key`. -Revocation (CRL/OCSP) and RFC 3161 timestamping are layered on top during both -signing and verification. +Revocation (CRL/OCSP) and RFC 3161 timestamping are layered on top during both signing and verification. ## Developer Workflow @@ -194,32 +103,22 @@ Build tooling is driven by the [`Makefile`](Makefile). Key targets: | `make vendor` | Vendors Go modules. | | `make check-line-endings` / `fix-line-endings` | Enforces LF line endings on `.go` files. | -Version metadata (`GitCommit`, `BuildMetadata`) is injected at link time from -git state — see the `LDFLAGS` block in the Makefile. +Version metadata (`GitCommit`, `BuildMetadata`) is injected at link time from git state — see the `LDFLAGS` block in the Makefile. ### CI/CD Pipeline (`.github/workflows/`) -``` - push / pull_request - │ - build.yml (Continuous Integration) - ├── check signed commits (PRs must be signed) - ├── setup Go 1.24 + module cache - ├── make download → make build - ├── golangci-lint (new-issue gating) - ├── make test (unit, race, coverage) - ├── make e2e-covdata (e2e against zot) - └── upload coverage → codecov.io - - push tag v* - │ - release-github.yml - └── GoReleaser (v2) → GitHub release with cross-platform binaries +```mermaid +flowchart TD + Trigger["push / pull_request"] + Build["build.yml (Continuous Integration)
check signed commits · setup Go 1.24 + cache
make download → make build · golangci-lint (new-issue gating)
make test (unit, race, coverage) · make e2e-covdata (e2e against zot)
upload coverage → codecov.io"] + Tag["push tag v*"] + Release["release-github.yml
GoReleaser (v2) → GitHub release with cross-platform binaries"] + + Trigger --> Build + Tag --> Release ``` -Additional workflows: `codeql.yml` (SAST), `scorecard.yml` (OpenSSF), -`license-checker.yml`, `stale.yml`, `add-to-project.yml`. Dependencies are kept -current by `dependabot.yml`. All commits must be **signed**. +Additional workflows: `codeql.yml` (SAST), `scorecard.yml` (OpenSSF), `license-checker.yml`, `stale.yml`, `add-to-project.yml`. Dependencies are kept current by `dependabot.yml`. All commits must be **signed**. ## User-Facing CLI Workflows @@ -260,52 +159,6 @@ notation key add --plugin myplugin --id mykey notation sign --key mykey registry.example.com/app:v1 ``` -## Improvement Opportunities - -The following are suggestions, not existing commitments. They are ordered by -approximate value-to-effort. - -### Documentation & onboarding -- **This document** — keep `ARCHITECTURE.md` linked from `README.md` and - `building.md` so new contributors have a map of the codebase. -- Add a short **"first contribution" walkthrough** (build → run a unit test → - run one e2e case) to `building.md`; currently it only covers `make install`. - -### Developer workflow / CI -- **Split CI jobs** — unit and e2e run in one job; separating them (with e2e as - a matrix over registry backends) improves signal and parallelism. -- **Cache e2e registry images** to reduce flakiness and runtime. -- **Burn down the lint backlog.** `make lint` is adopted incrementally - (`new-from-merge-base` in `.golangci.yml`) so only new issues fail CI. Roughly ~76 - pre-existing findings remain; clearing them lets `new-from-merge-base` be removed to - enforce linting across the whole tree. -- **Pin and document the Go toolchain** via a `go.work`/toolchain directive so - local and CI builds are reproducible. - -### Codebase / architecture -- **Consolidate reference-resolution logic.** `registry.go` and `manifest.go` - both handle registry-vs-OCI-layout branching; a single `target resolver` - abstraction would reduce duplication across `sign`/`verify`/`list`/`inspect`. -- **Unify OCI and blob flows.** Signing/verification exist in near-parallel OCI - and blob variants; extracting a shared orchestration interface (signer + - target + options) would cut duplicated flag/plumbing code. -- **Structured error taxonomy.** Extend `cmd/notation/internal/errors` into a - consistent, exit-code-mapped error hierarchy so scripts can reliably branch on - failure classes (network vs. policy vs. crypto). -- **Machine-readable output everywhere.** `--output json` is available on some - commands (inspect/verify); making it uniform across `list`, `sign`, and `key` - would improve scriptability and CI integration. - -### User experience -- **Progress + diagnostics.** A consistent `--debug`/verbosity story (already - partly present via `trace/`) surfaced uniformly across commands aids - troubleshooting of registry/auth failures. -- **`notation doctor`** — a diagnostic command that validates config directory, - trust policy syntax, trust-store contents, and registry connectivity in one - shot would shorten support loops. - --- -*This document reflects the repository state at the time of writing. When -command wiring in `cmd/notation/main.go` or the package layout changes, update -the corresponding sections here.* +*This document reflects the repository state at the time of writing. When command wiring in `cmd/notation/main.go` or the high-level structure changes, update the corresponding sections here.* From 781b0118d5355b04d007102da8a79a5c1768487d Mon Sep 17 00:00:00 2001 From: Tatsat Mishra Date: Mon, 3 Aug 2026 17:32:33 +1200 Subject: [PATCH 4/6] docs: redesign mermaid diagrams and clarify Trust Model source of truth - Redesign all mermaid diagrams for readability: flat top-down layered tree for the high-level architecture (no cramped nested subgraphs), simple left-to-right pipelines for sign/verify workflows, and a two-lane CI/CD diagram. Verified rendering via mermaid-cli. - Add a callout to the Trust Model section pointing to notaryproject/specifications as the source of truth; this doc is a practical implementation summary, not a restatement of the spec. Signed-off-by: Tatsat Mishra --- ARCHITECTURE.md | 66 ++++++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 5772a7db2..86d1cbbb1 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -35,14 +35,14 @@ For package- and symbol-level detail, see the Go documentation (`go doc ./...` o ```mermaid flowchart TD - CLI["CLI Layer — cmd/notation/*.go (Cobra commands)
sign · verify · list · inspect · login/logout · key
subcommands: blob/ · cert/ · plugin/ · policy/"] - Internal["CLI-internal — cmd/notation/internal/
flag · display · sign (GetSigner) · verify (GetVerifier)
truststore · experimental · errors · plugin"] - Utils["Shared utils — internal/
auth · config · envelope · httputil
revocation · x509 · osutil · trace · version"] - Libs["External Notary libs
notation-go (sign/verify)
notation-core-go (crypto)
oras-go (registry)"] - - CLI -->|delegates to| Internal - Internal -->|uses| Utils - Internal -->|uses| Libs + A["CLI layer — cmd/notation/
sign · verify · list · inspect · login · key
+ blob/ · cert/ · plugin/ · policy/"] + B["CLI-internal — cmd/notation/internal/
flag · display · sign · verify
truststore · experimental · errors · plugin"] + C["Shared utils — internal/
auth · config · envelope
httputil · revocation · x509"] + D["External Notary libraries
notation-go · notation-core-go · oras-go"] + + A --> B + B --> C + B --> D ``` The package layout under these trees is documented in the Go source itself; run `go doc ./cmd/notation/...` or `go doc ./internal/...` for the authoritative, always-current listing. @@ -52,33 +52,30 @@ The package layout under these trees is documented in the Go source itself; run ### Signing (`runSign`, `cmd/notation/sign.go`) ```mermaid -flowchart TD - A["sign.GetSigner
notation-go signer (local key pair OR plugin signer)"] - B["getRepository
oras OCI repository (remote registry or OCI layout)"] - C["prepareSigningOpts → notation.SignOptions
(envelope media type, expiry, plugin config,
user metadata, optional TSA timestamper + revocation)"] - D["resolveReference
tag resolved to immutable digest"] - E["notation.SignOCI(ctx, signer, sigRepo, opts)
notation-go signs and PUSHES the signature to the
registry as an OCI referrer of the target artifact"] - - A --> B --> C --> D --> E +flowchart LR + A["GetSigner
local key or plugin"] --> B["getRepository
registry or OCI layout"] + B --> C["prepareSigningOpts
envelope · expiry · TSA · revocation"] + C --> D["resolveReference
tag → digest"] + D --> E["notation.SignOCI
pushes signature as OCI referrer"] ``` ### Verification (`runVerify`, `cmd/notation/verify.go`) ```mermaid -flowchart TD - A["verify.GetVerifier
verifier with X.509 trust store, OCI trust policy
(trustpolicy.LoadOCIDocument), revocation validators
(CRL/OCSP), plugin manager"] - B["getRepository + resolveReference"] - C["notation.Verify(ctx, sigVerifier, sigRepo, opts)"] - D["ComposeVerificationFailurePrintout (on failure)"] - E["display handler renders result (tree / json / text)"] - - A --> B --> C --> D --> E +flowchart LR + A["GetVerifier
trust store · trust policy · revocation · plugins"] --> B["getRepository +
resolveReference"] + B --> C["notation.Verify"] + C -->|failure| D["ComposeVerification
FailurePrintout"] + C --> E["display handler
tree · json · text"] + D --> E ``` Blob commands mirror these flows using `notation.BlobSigner` / `BlobVerifier`. ## Trust Model +> The formal trust-policy specification lives in [notaryproject/specifications](https://github.com/notaryproject/specifications), which is the source of truth. The summary below is a practical orientation to how this CLI implements that spec, not a restatement of it. + Verification is governed by three on-disk artifacts, all under the Notation config directory (overridable with `NOTATION_CONFIG`): 1. **Trust store** — X.509 CA/certificate roots under `truststore/x509///`, managed by `notation cert`. @@ -109,13 +106,20 @@ Version metadata (`GitCommit`, `BuildMetadata`) is injected at link time from gi ```mermaid flowchart TD - Trigger["push / pull_request"] - Build["build.yml (Continuous Integration)
check signed commits · setup Go 1.24 + cache
make download → make build · golangci-lint (new-issue gating)
make test (unit, race, coverage) · make e2e-covdata (e2e against zot)
upload coverage → codecov.io"] - Tag["push tag v*"] - Release["release-github.yml
GoReleaser (v2) → GitHub release with cross-platform binaries"] - - Trigger --> Build - Tag --> Release + subgraph CI["build.yml — on push / pull_request"] + direction TB + S1["Check signed commits"] --> S2["Setup Go 1.24 + module cache"] + S2 --> S3["make build"] + S3 --> S4["golangci-lint
new-issue gating"] + S4 --> S5["make test
unit · race · coverage"] + S5 --> S6["make e2e-covdata
against zot"] + S6 --> S7["Upload coverage
to codecov.io"] + end + + subgraph Release["release-github.yml — on tag v*"] + direction TB + T1["GoReleaser v2"] --> T2["GitHub release
cross-platform binaries"] + end ``` Additional workflows: `codeql.yml` (SAST), `scorecard.yml` (OpenSSF), `license-checker.yml`, `stale.yml`, `add-to-project.yml`. Dependencies are kept current by `dependabot.yml`. All commits must be **signed**. From c08ac102a038e061ffc3579d69fa5740a72265b1 Mon Sep 17 00:00:00 2001 From: Tatsat Mishra Date: Mon, 3 Aug 2026 17:40:26 +1200 Subject: [PATCH 5/6] docs: polish High-Level Architecture diagram styling Color-code each layer (CLI, CLI-internal, shared utils, external libs), bold the package paths, and label edges (delegates to / built on / calls) so relationships are explicit rather than implied by bare arrows. Verified rendering locally with mermaid-cli before pushing. Signed-off-by: Tatsat Mishra --- ARCHITECTURE.md | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 86d1cbbb1..e3ab23e85 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -35,14 +35,24 @@ For package- and symbol-level detail, see the Go documentation (`go doc ./...` o ```mermaid flowchart TD - A["CLI layer — cmd/notation/
sign · verify · list · inspect · login · key
+ blob/ · cert/ · plugin/ · policy/"] - B["CLI-internal — cmd/notation/internal/
flag · display · sign · verify
truststore · experimental · errors · plugin"] - C["Shared utils — internal/
auth · config · envelope
httputil · revocation · x509"] - D["External Notary libraries
notation-go · notation-core-go · oras-go"] - - A --> B - B --> C - B --> D + A("CLI layer
cmd/notation/
sign · verify · list · inspect · login · key
+ blob/ · cert/ · plugin/ · policy/") + B("CLI-internal
cmd/notation/internal/
flag · display · sign · verify
truststore · experimental · errors · plugin") + C("Shared utilities
internal/
auth · config · envelope
httputil · revocation · x509") + D("External Notary libraries
notation-go · notation-core-go · oras-go") + + A -->|"delegates to"| B + B -->|"built on"| C + B -->|"calls"| D + + classDef cli fill:#dbeafe,stroke:#1d4ed8,stroke-width:1.5px,color:#1e3a8a; + classDef internal fill:#fef3c7,stroke:#b45309,stroke-width:1.5px,color:#78350f; + classDef utils fill:#dcfce7,stroke:#15803d,stroke-width:1.5px,color:#14532d; + classDef libs fill:#f3e8ff,stroke:#7e22ce,stroke-width:1.5px,color:#581c87; + + class A cli + class B internal + class C utils + class D libs ``` The package layout under these trees is documented in the Go source itself; run `go doc ./cmd/notation/...` or `go doc ./internal/...` for the authoritative, always-current listing. From 12b382b024fd47338ed46fb726ca27e11a7b353e Mon Sep 17 00:00:00 2001 From: Tatsat Mishra Date: Mon, 3 Aug 2026 19:16:19 +1200 Subject: [PATCH 6/6] docs: drop ARCHITECTURE.md to keep this PR focused on lint tooling Per review discussion, split scope: keep this PR limited to the golangci-lint tooling (.golangci.yml, make lint, CI wiring) and move the architecture overview to a separate follow-up PR for its own focused review. Signed-off-by: Tatsat Mishra --- ARCHITECTURE.md | 178 ------------------------------------------------ README.md | 1 - building.md | 2 - 3 files changed, 181 deletions(-) delete mode 100644 ARCHITECTURE.md diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md deleted file mode 100644 index e3ab23e85..000000000 --- a/ARCHITECTURE.md +++ /dev/null @@ -1,178 +0,0 @@ -# Notation Architecture - -Notation is the [Notary Project](https://notaryproject.dev) CLI for signing and verifying artifacts in the OCI registry ecosystem. It stores signatures as OCI **referrers** alongside the artifact they sign — conceptually similar to git commit signing, but generic and usable for arbitrary security purposes. - -- **Module:** `github.com/notaryproject/notation/v2` (Go `>= 1.24`) -- **Entry point:** [`cmd/notation/main.go`](cmd/notation/main.go) → `run()` assembles the root Cobra command and registers all subcommands -- **Core frameworks:** [Cobra](https://github.com/spf13/cobra) (CLI), [`oras-go/v2`](https://oras.land) (OCI registry & OCI-layout I/O) -- **Notary libraries** (where the real work happens): - - `notation-go` — sign / verify / list algorithms, trust policy, plugin manager - - `notation-core-go` — signature envelopes, X.509, revocation (CRL/OCSP) - - `notation-plugin-framework-go` — plugin contract - - `tspclient-go` — RFC 3161 timestamping - -For package- and symbol-level detail, see the Go documentation (`go doc ./...` or [pkg.go.dev](https://pkg.go.dev/github.com/notaryproject/notation/v2)); this document intentionally stays at the architectural level so it does not drift from the code. - -## Table of Contents - -- [Design Philosophy](#design-philosophy) -- [High-Level Architecture](#high-level-architecture) -- [Core Workflows](#core-workflows) -- [Trust Model](#trust-model) -- [Developer Workflow](#developer-workflow) -- [User-Facing CLI Workflows](#user-facing-cli-workflows) - -## Design Philosophy - -1. **Thin CLI layer.** Command files in `cmd/notation/` only parse flags and orchestrate. All cryptographic algorithms live in `notation-go` / `notation-core-go`. This keeps the CLI auditable and lets the libraries be reused by other tools. -2. **Centralized registry plumbing.** All OCI registry, auth, and OCI-layout access flows through [`registry.go`](cmd/notation/registry.go) (`getRepository`), so transport, credentials, and referrers-fallback logic live in one place. -3. **Two `internal/` trees, two concerns.** - - `cmd/notation/internal/` — CLI *presentation* concerns (flags, output rendering, signer/verifier construction, experimental gating). - - `internal/` — reusable *lower-level* utilities (auth store, config cache, HTTP client, revocation, x509, version). -4. **Pluggable everything.** Signing keys, verification, and revocation are all pluggable via the plugin framework and JSON trust policies. - -## High-Level Architecture - -```mermaid -flowchart TD - A("CLI layer
cmd/notation/
sign · verify · list · inspect · login · key
+ blob/ · cert/ · plugin/ · policy/") - B("CLI-internal
cmd/notation/internal/
flag · display · sign · verify
truststore · experimental · errors · plugin") - C("Shared utilities
internal/
auth · config · envelope
httputil · revocation · x509") - D("External Notary libraries
notation-go · notation-core-go · oras-go") - - A -->|"delegates to"| B - B -->|"built on"| C - B -->|"calls"| D - - classDef cli fill:#dbeafe,stroke:#1d4ed8,stroke-width:1.5px,color:#1e3a8a; - classDef internal fill:#fef3c7,stroke:#b45309,stroke-width:1.5px,color:#78350f; - classDef utils fill:#dcfce7,stroke:#15803d,stroke-width:1.5px,color:#14532d; - classDef libs fill:#f3e8ff,stroke:#7e22ce,stroke-width:1.5px,color:#581c87; - - class A cli - class B internal - class C utils - class D libs -``` - -The package layout under these trees is documented in the Go source itself; run `go doc ./cmd/notation/...` or `go doc ./internal/...` for the authoritative, always-current listing. - -## Core Workflows - -### Signing (`runSign`, `cmd/notation/sign.go`) - -```mermaid -flowchart LR - A["GetSigner
local key or plugin"] --> B["getRepository
registry or OCI layout"] - B --> C["prepareSigningOpts
envelope · expiry · TSA · revocation"] - C --> D["resolveReference
tag → digest"] - D --> E["notation.SignOCI
pushes signature as OCI referrer"] -``` - -### Verification (`runVerify`, `cmd/notation/verify.go`) - -```mermaid -flowchart LR - A["GetVerifier
trust store · trust policy · revocation · plugins"] --> B["getRepository +
resolveReference"] - B --> C["notation.Verify"] - C -->|failure| D["ComposeVerification
FailurePrintout"] - C --> E["display handler
tree · json · text"] - D --> E -``` - -Blob commands mirror these flows using `notation.BlobSigner` / `BlobVerifier`. - -## Trust Model - -> The formal trust-policy specification lives in [notaryproject/specifications](https://github.com/notaryproject/specifications), which is the source of truth. The summary below is a practical orientation to how this CLI implements that spec, not a restatement of it. - -Verification is governed by three on-disk artifacts, all under the Notation config directory (overridable with `NOTATION_CONFIG`): - -1. **Trust store** — X.509 CA/certificate roots under `truststore/x509///`, managed by `notation cert`. -2. **Trust policy** — a JSON document (`trustpolicy.oci.json` / `trustpolicy.blob.json`) mapping registry scopes to trust stores, signature verification levels, and trusted identities; managed by `notation policy` / `notation blob policy`. -3. **Signing keys** — the key list in `config.json`, managed by `notation key`. - -Revocation (CRL/OCSP) and RFC 3161 timestamping are layered on top during both signing and verification. - -## Developer Workflow - -Build tooling is driven by the [`Makefile`](Makefile). Key targets: - -| Command | Description | -|---------|-------------| -| `make build` | Builds `bin/notation` with version info injected via `-ldflags`. | -| `make install` | Builds and copies `notation` to `~/bin/`. | -| `make test` | Runs unit tests with race detector and coverage (`coverage.txt`). | -| `make lint` | Runs `golangci-lint` using `.golangci.yml` (adopted incrementally via `new-from-merge-base`). | -| `make e2e` | Builds the CLI and runs the Ginkgo e2e suite against a `zot` registry. | -| `make e2e-covdata` | Runs e2e with binary coverage instrumentation. | -| `make download` | Downloads Go module dependencies. | -| `make vendor` | Vendors Go modules. | -| `make check-line-endings` / `fix-line-endings` | Enforces LF line endings on `.go` files. | - -Version metadata (`GitCommit`, `BuildMetadata`) is injected at link time from git state — see the `LDFLAGS` block in the Makefile. - -### CI/CD Pipeline (`.github/workflows/`) - -```mermaid -flowchart TD - subgraph CI["build.yml — on push / pull_request"] - direction TB - S1["Check signed commits"] --> S2["Setup Go 1.24 + module cache"] - S2 --> S3["make build"] - S3 --> S4["golangci-lint
new-issue gating"] - S4 --> S5["make test
unit · race · coverage"] - S5 --> S6["make e2e-covdata
against zot"] - S6 --> S7["Upload coverage
to codecov.io"] - end - - subgraph Release["release-github.yml — on tag v*"] - direction TB - T1["GoReleaser v2"] --> T2["GitHub release
cross-platform binaries"] - end -``` - -Additional workflows: `codeql.yml` (SAST), `scorecard.yml` (OpenSSF), `license-checker.yml`, `stale.yml`, `add-to-project.yml`. Dependencies are kept current by `dependabot.yml`. All commits must be **signed**. - -## User-Facing CLI Workflows - -### Sign & verify an image (registry) - -```sh -# 1. Authenticate to the registry -notation login registry.example.com - -# 2. Register a signing key (or use a plugin/KMS key) -notation cert generate-test --default "example.com" - -# 3. Sign the artifact (signature stored as an OCI referrer) -notation sign registry.example.com/app:v1 - -# 4. Configure a trust policy and verify -notation policy import ./trustpolicy.json -notation verify registry.example.com/app:v1 - -# 5. Inspect / list signatures -notation list registry.example.com/app:v1 -notation inspect registry.example.com/app:v1 -``` - -### Detached blob signing - -```sh -notation blob policy import ./trustpolicy.blob.json -notation blob sign ./artifact.tar.gz # emits a detached .sig -notation blob verify --signature artifact.tar.gz.sig ./artifact.tar.gz -``` - -### Plugin / KMS-backed signing - -```sh -notation plugin install --file ./notation-myplugin.tar.gz -notation key add --plugin myplugin --id mykey -notation sign --key mykey registry.example.com/app:v1 -``` - ---- - -*This document reflects the repository state at the time of writing. When command wiring in `cmd/notation/main.go` or the high-level structure changes, update the corresponding sections here.* diff --git a/README.md b/README.md index d628b9285..68a86b4be 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,6 @@ Notary Project is a [CNCF Incubating project](https://www.cncf.io/projects/notar ### Development and Contributing -- [Architecture overview](/ARCHITECTURE.md) - [Build Notation from source code](/building.md) - [Governance for Notary Project](https://github.com/notaryproject/.github/blob/master/GOVERNANCE.md) - [Maintainers and reviewers list](https://github.com/notaryproject/notation/blob/main/CODEOWNERS) diff --git a/building.md b/building.md index f7648606b..4e03d271d 100644 --- a/building.md +++ b/building.md @@ -6,8 +6,6 @@ The notation repo contains the following: Building above binaries require [golang](https://golang.org/dl/) with version `>= 1.24`. -> For a map of the codebase and how the CLI is structured, see [ARCHITECTURE.md](/ARCHITECTURE.md). - ## Windows with WSL or Linux - Build the binaries, installing them to: