Conversation
Brings the CLI half of the GOBL Net effort across from
`invopop/gobl@net` (PR #785, where the library half lives), now that
the CLI / ops / MCP / api / wasm directories have moved to this repo.
New commands:
- `gobl init <domain>` — scaffolds `~/.config/gobl/<domain>/` (an
auto-generated ES256 keypair + a `party.json` template pre-filled
with a `gobl:<domain>` endpoint).
- `gobl net who <address> --from <domain>` — authenticated mutual
party exchange; POSTs a signed request and returns the target's
verified `org.Party` envelope (any authority countersignatures
carried along).
- `gobl net send <envelope> --to <domain> --from <domain>` —
delivers a signed envelope to a remote `/inbox`.
- `gobl net serve` — HTTPS server with `/.well-known/gobl/keys/<kid>`
(per-key lookup), `/.well-known/jwks.json` (bulk JWK Set, sorted
by `valid_from` descending), `/who`, and `/inbox`. Multi-tenant:
auto-discovers every `<domain>/` directory under the config dir and
routes by `Host`. Open CORS (`*` + OPTIONS preflight → 204) so
browser-based JOSE tooling can fetch the JWKS. Optional per-domain
`allow.json` gates `/who` and `/inbox` by signer address. ACME
issues for all discovered domains.
Extended commands:
- `gobl sign --domain X [--to Y]` stamps `iss=gobl:X` / `aud=gobl:Y`
into the signed payload.
- `gobl verify` gains `--address` / `--remote` for remote key
discovery via the new per-key endpoint.
- `gobl keygen` is deprecated in favour of `gobl init`.
Operator output:
- Top-level `--json` flag flips all operator-facing log output between
human-readable text (default) and structured JSON (one entry per
line). Logs go to stderr; result output (signed envelopes, /who
party JSON, version JSON) stays on stdout. `slog` is set up on the
root command's `PersistentPreRunE` (not `cobra.OnInitialize`, which
would race in parallel tests). CLI errors emit a single
`command failed` entry with `key` / `message` / `faults`.
- `gobl net serve` emits structured access logs:
`http_request` per request plus handler-specific
`keys.lookup`, `jwks.served`, `who.exchange` / `who.rejected`,
`inbox.accepted` / `inbox.rejected`, `inbox.write_failed`. Startup
messages (`generated keypair`, `initialised domain`,
`GOBL Net listening`, `ACME enabled`, `Shutting down`) are
structured too.
On-disk layout (operator-visible):
- `<config>/<domain>/{private.jwk, keys/<kid>.json, party.json,
allow.json, inbox/}`. One file per `kid` (filename equals `kid`,
validated at startup) — the model maps 1-to-1 to a future
row-per-kid database. Rotation is filesystem ops.
`gobl net serve --keys` → `--keys-dir`.
Security:
- `/inbox` re-parses the envelope's UUID with `uuid.Parse` before
writing to disk as a defence-in-depth check against path
traversal. UUIDs already pass `env.Validate()` +
`uuid.HasTimestamp` + the strict 36-char `[0-9a-f-]` format check
from `google/uuid`; the re-parse keeps the filesystem write site
self-contained.
The `gobl.dev/cmd/gobl` and `gobl.dev/internal/ops` trees match
`gobl@main`'s pre-extraction layout, so the bulk of the port applies
verbatim — `cmd/gobl/main.go` and `internal/ops/bulk_test.go` (which
gobl.dev had already edited) merged by hand. The `gobl` module is
pinned to the post-PR-785-merge `ff04d20e` commit, which itself
merges `cli-to-gobldev` into `net`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## cli-trial #2 +/- ##
=============================================
+ Coverage 72.71% 77.95% +5.23%
=============================================
Files 47 57 +10
Lines 1983 2908 +925
=============================================
+ Hits 1442 2267 +825
- Misses 463 527 +64
- Partials 78 114 +36 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Adds operator-facing documentation for the new GOBL Net commands ported onto this repo in the previous commit: `gobl init`, `gobl net who`, `gobl net send`, and `gobl net serve` (the reference server). Also extends `gobl sign` and `gobl verify` rows in the command table with the new `--domain` / `--to` / `--address` / `--remote` flags. The new section covers what an operator needs to deploy a node: on-disk identity layout, startup checks, TLS sources (`--acme-live`/`--acme-test`/`--tls-cert`), party-derived ACME defaults, the three operational stances, Docker recipes (incl. unprivileged), `--json` logging, the structured-access-log catalog, and CLI error reporting. Points readers at `gobl/net/README.md` for the wire-protocol spec (addresses, key format and validity windows, signed payload, per-kid + JWKS + /who + /inbox endpoints, errors, security model) — that file is now scoped to the spec alone. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add TestApprovedAddonsAreBundled: every key in tax.ApprovedAddons must resolve once the bundle is loaded, catching a missing blank import (or a major-version registry split) in CI. The test surfaced that the bundle no longer imported github.com/invopop/ gobl/addons, so neither the in-core addons nor the approved-addon registry (addons/external.go) were being registered — restore that import alongside the external gobl.fr.ctc/addon. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`POST /.well-known/gobl/inbox` previously enforced `aud == self` only when the signature carried an aud at all; a signature without an aud was let through. That meant the same valid envelope could be POSTed to any number of inboxes with no replay protection from the signature alone. Tighten the handler to require `aud != ""` *and* `aud == self`. Envelopes without an audience get a new `aud_missing` rejection reason in the access log; existing `aud_mismatch` semantics are unchanged. The status code stays `401 Unauthorized` for both. The library-level `net.Client.VerifyEnvelope` keeps `expectedAud` optional — it serves non-inbox callers too (e.g. archival verifiers that just want issuer attestation). The strict "must be bound to me" rule lives in the inbox handler, where the receiver always knows its own address. Tests: - TestNetServeInboxAudMismatch: comment refreshed; behaviour unchanged (aud != self → 401). - TestNetServeInboxAudMissing: new — envelope signed with empty aud is rejected with 401. Also bumps the `github.com/invopop/gobl` pin to pull in the matching spec/IDN/x5c changes on the gobl `net` branch (commit 0dd345f0), and refreshes the README + CHANGELOG to flag the inbox aud requirement and the new `aud_missing` access-log reason. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Become the base of operations: gobl CLI + gobl.dev web/API + wasm
Resolves Dependabot CRITICAL/HIGH advisories flagged in Vanta. Bumped: axios -> 1.18.0, tmp -> 0.2.7, esbuild -> 0.28.1, fast-uri -> 4.0.0
chore(deps): bump vulnerable dependencies (CRITICAL/HIGH)
GOBL 0.501.0 released
Fixes the Fly deploy build: the Dockerfile pinned golang:1.24-alpine while go.mod requires go 1.25.0, so `flyctl deploy` could not build the module. Bumped the builder image to golang:1.25-alpine. Updates the wasm dev/test dependencies to clear open Dependabot alerts (supersedes #6-#12): - wasm/worker: vite 6 -> 8, postcss -> 8.5.15 (0 vulns) - wasm: cypress 14 -> 15 (drops vulnerable uuid), and patches the transitive form-data 4.0.6, joi 17.13.4, qs 6.15.2, ip-address 10.x, socks 2.8.9; bumped the ws override to ^8.21.0. Remaining: 3 moderate dev-only advisories in the markdownlint-cli chain (markdown-it, js-yaml) have no forward fix published — the only "fix" is a downgrade to markdownlint-cli 0.43.0. These are DoS-on-malicious-input issues in a linter that only runs against our own files in dev/CI, so the downgrade is not worth the regression. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
chore: fix deploy Go version and update vulnerable npm deps
v0.0.4 is the first tag containing the Flow 6 state-handling work (the previous v0.0.3 predated it due to a merge-order issue, now fixed by gobl.fr.ctc#4). The bundle picks up the new flow6 behavior for the playground / CLI / MCP with no code changes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bump gobl.fr.ctc to v0.0.4 (Flow 6 state handling)
Bump gobl.sa.zatca
Add bundle/bundle_test.go which fails if any addon on GOBL's approved external list (tax.ApprovedAddons) is not registered through the bundle, guarding against the bundle drifting out of sync with the addons GOBL endorses. To make the bundle complete, import the remaining approved addon modules (br.nfe, br.nfse, mx.cfdi, pt.saft) alongside the existing fr.ctc and sa.zatca imports. Bump gobl v0.501.0 -> v0.502.1. In v0.502.x several addons (mx, br, pt) moved out of core into standalone modules, so internal/ops tests now blank-import the bundle to register the same addon set the production binaries use (restores the mx food-vouchers / fuel-account-balance schemas in the schema list). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add bundle addon-coverage test; bump gobl to v0.502.2
Add tzdata to container
# Conflicts: # bundle/bundle.go # bundle/bundle_test.go # go.mod # go.sum # internal/ops/sign.go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Brings the CLI half of the GOBL Net effort across from
invopop/gobl@net(PR#785, where the library half lives) into this repo, now that
cmd/gobl/,internal/ops/,internal/mcp/,pkg/api/, andwasm/live here.The
goblmodule is pinned toff04d20e7388— the post-merge tip ofthe
netbranch in gobl aftercli-to-gobldevwas merged in.New commands
gobl init <domain>— scaffold~/.config/gobl/<domain>/(ES256keypair +
party.jsontemplate with a pre-filledgobl:<domain>endpoint).
gobl net who <address> --from <domain>— authenticated mutualparty exchange; returns the target's verified
org.Partyenvelope.
gobl net send <envelope> --to <domain> --from <domain>— delivera signed envelope to a remote
/inbox.gobl net serve— HTTPS server with/.well-known/gobl/keys/<kid>(per-key lookup),/.well-known/jwks.json(bulk JWK Set sorted byvalid_fromdesc),
/who, and/inbox. Multi-tenant. ACME. Open CORS forbrowser-based JOSE tooling. Optional
allow.jsongate.Extended commands
gobl sign --domain X [--to Y]stampsiss=gobl:X/aud=gobl:Yinto the signed payload.gobl verifygains--address/--remotefor remote keydiscovery.
gobl keygenis deprecated in favour ofgobl init.Operator output
--jsonflag toggles all operator-facing log output betweentext (default) and JSON via
log/slog. Logs go to stderr; resultoutput (signed envelopes, /who party JSON, version JSON) stays on
stdout.
slogis set up inPersistentPreRunEon the rootcommand (not
cobra.OnInitialize, which would race in paralleltests).
http_request,keys.lookup,jwks.served,who.exchange/who.rejected,inbox.accepted/inbox.rejected,inbox.write_failed) plusstructured startup messages.
On-disk layout
<config>/<domain>/{private.jwk, keys/<kid>.json, party.json, allow.json, inbox/}— one file perkid(filename equalskid,validated at startup). Maps 1-to-1 to a future row-per-kid
database.
Security
/inboxre-parses the document UUID withuuid.Parsebeforewriting to disk, as a defence-in-depth check against path
traversal (alongside the existing strict 36-char format check from
google/uuid).Test plan
go build ./...clean.go vet ./...clean.go test -race ./...green acrossapi,cmd/gobl,internal/mcp,internal/ops,wasm.golangci-lint run ./...clean.gobl init smoke.example(UUIDv7 kid),followed by
gobl sign --domain alice.example --to bob.example→ signed payload
{uuid, dig, iss=gobl:alice.example, aud=gobl:bob.example, iat=<unix>}.🤖 Generated with Claude Code