Skip to content

feat(edge): Add the MASQUE provider adapter - #1151

Merged
privateip merged 2 commits into
mainfrom
fix/issue-975-adapter
Oct 27, 2026
Merged

privateip merged 2 commits into
mainfrom
fix/issue-975-adapter

Conversation

@privateip

@privateip privateip commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

MASQUE's CONNECT-IP server needs a trusted way to reach a tenant VPC through the Galactic Edge provider contract, and until now only a lab fixture provided one. This adds the provider adapter that both transports will use. It requests the attachment each grant names, waits for core to accept the connector's route, and forwards a packet only while the instance lease, the grant and the request are all current. Every refusal fails closed, and cleanup never removes another request's or a replacement's resources.

This is the bottom of a GitHub stack with #1152 on top, which moves the lab fixture onto the adapter and documents its operation. It was opened ready for review at the requester's request.

Compatibility and rollback

New package with no deployed caller. Core and its manifests do not change. Revert the commits to roll back.

Test plan

  • task build, task test:unit, task test:e2e and lint pass
  • Adapter tests and the envtest against core pass with -race
  • CI passes

Related to #975

The CONNECT-IP server in internal/edge/connectip needs an Admission and a PacketBackend that reach a gVPC through the Galactic Edge provider contract. Until now only a test fixture implemented them, with static credentials and a lease check as its only per-request gate.

internal/edge/masque is that adapter. One Adapter runs in a provider pod. It registers the pod's EdgeInstance and holds its lease on its own renewal worker. For each grant an Authorizer returns, it requests the service's PacketAccess attachment, verifies its immutable references, waits until galactic-edge programs it, opens only the TUN device its status names and reports Ready. It then claims the connector's /96 EdgeRoute and admits the request only once core accepts that claim for the attachment's UID and the lease's incarnation and epoch. Every packet in either direction is checked against the lease, the grant deadline and the request's own state. A connector has at most one open request; another is refused before any preparation.

Requests of one service share its attachment and device. Ending one request removes only its own packet registration; the connector's last request releases its claim, and an attachment left idle is deleted with its UID as a precondition, so a stale delete cannot remove a replacement. Every refusal fails closed: an attachment core refuses, a VPC or node that does not match the grant, a missing or unopenable device, a draining attachment, or a route core refuses outright. A restarted process adopts the pod's attachments, reporting them not Ready until it serves them again, and claims every route again under a lease it acquires. A claim that moves to another attachment or lease ends the requests admitted under the old one, and a late release never releases a claim a newer request made.

Key changes:
- Add Adapter, Grant and Authorizer, with the attachment, route and request lifecycles described above
- Count a full device as a dropped packet instead of ending the request
- Bound every wait for another request's preparation, and every check's API calls, by a deadline
- Unit tests for each refusal, shared attachments, duplicate requests, expiry, idle deletion, restart, shutdown order, a late release racing a new claim, a lease change, a claim moving attachment and a queued request's deadline
- An envtest that runs the adapter as the provider pod's pod-bound identity against core's attachment and route controllers and the shipped RBAC and admission policies
Shutdown took its snapshot of attachments and routes while requests could still be preparing. A request that created an attachment after the snapshot left it behind until a later process adopted and deleted it. Shutdown now cancels every preparation in flight and waits, within its deadline, for those requests to give up before it cleans up.

A restarted process also adopted an attachment that was already being deleted and wrote its Ready condition. It now leaves that object alone, and a request for its service waits for the release before requesting a new attachment.
@scotwells

Copy link
Copy Markdown
Contributor

In attachment.go:256–278, three consecutive update conflicts followed by successful reads leave err == nil, so setReady reports success without writing Ready=True. Please return the last update error when retries run out and cover this case in a test, so preparation cannot succeed with readiness still unset.

@privateip

Copy link
Copy Markdown
Collaborator Author

This PR went through two review passes before being marked ready.

First pass, at f313941: pr-adversary returned VERDICT merge with two warnings (the Shutdown snapshot could race an in-flight Admit, and adopting a terminating attachment had no test). pr-conventions-reviewer returned VERDICT hold over the PR body (too long, too much jargon), the PR opening as ready rather than draft, and the ownership question. The ownership question is settled by issue #975, which assigns the adapter to this repository, and the PR stays ready. Commit 13fce68 fixes both warnings and the body was rewritten.

Second pass, at 13fce68: pr-rereviewer returned VERDICT merge. It confirmed both warnings are fixed and that each new test fails when its fix is reverted. pr-conventions-reviewer returned VERDICT merge. Its remaining notes on the body (stack reference, test-plan wording) are fixed in the current body, and the commit subject length is within what CLAUDE.md allows.

What the reviewers ran: go test -race on the masque package (count 3 and 4), go vet, golangci-lint, a tamper test of each fix, gh pr checks, and diff scans. The session also ran task build, task test:unit (including the envtest TestAgainstCore), task test:e2e uncached, lint and docs:check on the top of the stack.

Applied: both first-pass warnings, in 13fce68.

One nit is open: the admitting.Wait in Shutdown has no test that fails if it is removed.

CI on 13fce68: every check passed (Build, Lint, Unit Tests, Unit Tests (root), E2E Tests, Manifests, Documentation, Service API bundle, the image and bundle publish jobs, CLA).

Auto-merge is not enabled. This PR is the bottom of a GitHub native stack with #1152, which stays draft until a lab run. Stacked PRs cannot use auto-merge, so the stack is merged later through gh stack merge on the top PR after approval. The ruleset review requirements apply as usual.

@privateip
privateip merged commit d2ef1ad into main Oct 27, 2026
23 checks passed
@privateip
privateip deleted the fix/issue-975-adapter branch October 27, 2026 19:50
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.

3 participants