Skip to content

adminrpc: add per-service timeout field for TTL caveat support#234

Open
maml wants to merge 1 commit into
lightninglabs:masterfrom
maml:adminrpc-timeout-field
Open

adminrpc: add per-service timeout field for TTL caveat support#234
maml wants to merge 1 commit into
lightninglabs:masterfrom
maml:adminrpc-timeout-field

Conversation

@maml
Copy link
Copy Markdown

@maml maml commented Apr 18, 2026

Summary

Adds a timeout field to the admin-API Service, CreateServiceRequest, and UpdateServiceRequest messages so operators can configure a per-service TTL. When timeout > 0 the minter includes a _valid_until caveat in the L402 macaroon, expiring access after that many seconds.

Changes

Proto / generated code

  • adminrpc/admin.proto: add int64 timeout = 9 to Service and CreateServiceRequest; optional int64 timeout = 9 to UpdateServiceRequest (proto3 optional preserves the "not-set vs zero" distinction needed for partial updates).
  • Regenerated admin.pb.go, admin_grpc.pb.go, admin.swagger.json.

Database

  • Migration 000008_services_timeout: ALTER TABLE services ADD COLUMN timeout BIGINT NOT NULL DEFAULT 0.
  • Updated sqlc models, query, and generated Go code to include the timeout column.

Admin server (admin/server.go)

  • ListServices: populate Timeout on each returned Service.
  • CreateService: validate Timeout >= 0; store and return it.
  • UpdateService: honour the optional Timeout field; validate and update.

Proxy wiring (aperture.go, services.go)

  • mergeServicesFromDB: propagate Timeout from DB row → proxy.Service.
  • staticServiceLimiter: updated struct comment; added sync.RWMutex and a refresh(services) method that atomically rebuilds capabilities, constraints, and timeouts maps under write lock. All three Service* read methods acquire a read lock. newStaticServiceLimiter delegates to refresh to eliminate duplication.
  • createProxy: returns *staticServiceLimiter alongside the proxy.
  • Aperture: stores limiter *staticServiceLimiter. The UpdateServices closure calls a.limiter.refresh(s) before routing is updated — this ensures that on delete the limiter stops minting caveats for a service before the proxy stops routing to it.

Without the refresh wiring, staticServiceLimiter was a startup-time snapshot — admin-API mutations updated the DB and proxy routing but the minter continued using stale caveat maps for the lifetime of the process.

Tests

  • admin/server_test.go: TestCreateServiceWithTimeout, TestUpdateServiceTimeout, TestUpdateServiceCanSetTimeoutToZero, TestCreateServiceRejectsNegativeTimeout, TestUpdateServiceRejectsNegativeTimeout.
  • aperturedb/services_test.go: TestUpsertServiceTimeout.
  • services_test.go: TestRefreshRebuildsTimeouts, TestRefreshConcurrentReads (race-detector clean), TestRefreshCreateDelete.

Docs (docs/admin-api.md): document the timeout field and the AUTH_SCHEME_* enum.

Test plan

  • go test ./... passes
  • go test -race ./... passes (no data races)
  • Create a service via admin API with timeout: 60; mint an L402; verify _valid_until caveat is present and ~60 s in the future.
  • Update the service timeout to 0 via admin API; mint again; verify no _valid_until caveat.
  • Restart aperture; confirm timeout survives (loaded from DB via mergeServicesFromDB).

@maml maml force-pushed the adminrpc-timeout-field branch from 63a3e43 to 2b4f3a8 Compare April 18, 2026 18:25
Admin-API-registered services previously had Timeout=0 after the
mergeServicesFromDB merge, because the proto's Service message
lacked a timeout field. As a result
staticServiceLimiter.ServiceTimeouts never added a _valid_until
caveat for admin-API-sourced services, silently disabling the TTL
expiry mechanism documented in sample-conf.yaml.

This commit adds int64 timeout to:
  - Service
  - CreateServiceRequest
  - UpdateServiceRequest

and wires it through:
  - aperturedb services table (schema + migration 000008)
  - aperturedb/sqlc: models, query, generated services.sql.go
  - aperturedb/services.go ServiceParams
  - admin/server.go CreateService, UpdateService, ListServices
  - aperture.go mergeServicesFromDB (copy Timeout to proxy.Service)

No changes to staticServiceLimiter.ServiceTimeouts or the mint
pipeline -- they already check proxyService.Timeout > 0. This
commit surfaces the existing mechanism through the admin API
surface.

Other per-service fields (capabilities, constraints, ratelimits,
authwhitelistpaths, headers, rewrite, tlscertpath) have the same
gap and are intentionally deferred to follow-up PRs to keep this
change focused.
@maml maml force-pushed the adminrpc-timeout-field branch from 2b4f3a8 to 1861b68 Compare April 18, 2026 18:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant