Add workshop identity to workshopctl requests - #1017
Conversation
|
@tlm I can review it, but I think the tests are failing |
Expose UserProjects on the backend interface so callers can retrieve only the projects owned by the user in context without listing every user's projects. Reuse the new method in the LXD and fake backend implementations and return an empty result when the context does not identify a user.
Add middleware that copies an optional workshop instance ID header into the request context for downstream handlers. Define a shared typed context key and cover requests with and without the header while ensuring the next response function is always called.
Derive the test user's UID and GID from the user running the suite instead of assuming both are 1000. This allows LXD raw ID mapping to work on hosts where the test runner uses different numeric user and group IDs.
Add an instance ID to workshop runtime metadata and populate it from LXD's volatile UUID, normalized to match the value written to /etc/machine-id. Cover the mapping through the LXD backend integration suite.
Apply the workshop instance ID middleware to the workshopctl endpoint so a supplied instance ID is available to downstream request handling through the request context.
Use the invoking user's IDs for local integration runs, but retain the non-root workshop IDs when Spread executes the suite as root. This prevents LXD from trying to map host root into an unprivileged workshop instance.
7283024 to
d7624be
Compare
There was a problem hiding this comment.
🟡 Changes recommended
The new integration test can produce false positives without asserting that LXD’s volatile.uuid is present/non-empty before comparing normalized IDs.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR propagates a workshop “instance identity” through the system so workshopctl requests can be associated with the workshop instance they originated from, laying groundwork for later validation and routing decisions.
Changes:
- Add
InstanceIDtoworkshop.Workshop, derived from LXD’svolatile.uuidnormalized to the machine-id format. - Add
UserProjects(ctx)to the backend interface and use it for user-scoped project lookup in both LXD and fake backends. - Introduce daemon middleware to copy the optional
workshop-instance-idheader into request context and apply it to the/v1/workshopctlendpoint; update integration fixtures for UID/GID portability.
File summaries
| File | Description |
|---|---|
| internal/workshop/workshop.go | Adds Workshop.InstanceID field for propagating backend instance identity. |
| internal/workshop/lxd/tests/integration/workshop_test.go | Makes integration fixture UID/GID portable; adds an integration test for the exposed LXD-derived instance ID. |
| internal/workshop/lxd/lxd_backend.go | Derives and populates Workshop.InstanceID from LXD volatile.uuid (normalized). |
| internal/workshop/lxd/lxd_backend_project.go | Introduces UserProjects and refactors project listing to use it. |
| internal/workshop/lxd/lxd_backend_dns.go | Switches DNS CNAME generation to use UserProjects. |
| internal/workshop/fakebackend/backend.go | Implements UserProjects and reuses it from Projects. |
| internal/workshop/backend.go | Adds ContextWorkshopInstanceID and extends the backend interface with UserProjects. |
| internal/daemon/snapshot-ingredients.yaml | Includes Workshop.InstanceID in snapshot ingredient definitions. |
| internal/daemon/api.go | Wraps /v1/workshopctl POST handler with the new instance-id middleware. |
| internal/daemon/api_request.go | Adds middleware to copy workshop-instance-id header into request context. |
| internal/daemon/api_request_test.go | Adds unit tests validating middleware behavior with/without the header. |
Review details
- Files reviewed: 11/11 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| expected := strings.ReplaceAll(inst.Config["volatile.uuid"], "-", "") | ||
|
|
| func (s *Backend) userProjects(ctx context.Context) ([]workshop.Project, error) { | ||
| func (s *Backend) UserProjects(ctx context.Context) ([]workshop.Project, error) { | ||
| if _, ok := ctx.Value(workshop.ContextUser).(string); !ok { | ||
| return nil, nil |
There was a problem hiding this comment.
| return nil, nil | |
| return []workshop.Project{}, nil |
The interface's comment says it would return an empty slice, though, it's probably equivalent behavior here. I'm guessing the difference will show up if this would make it as a return value for /v1/projects (not quite likely either given it would be transformed into an API level struct).
There was a problem hiding this comment.
I would be inclined to leave it as is. len(nil) still returns 0 and append operations still work. i.e nill is safe value for slices in go.
Description
Lay the groundwork for associating workshopctl requests with the workshop instance from which they originated.
Add user-scoped project lookup to workshop backends and expose the LXD instance UUID on loaded workshop metadata. The UUID is normalized to match the value written to
/etc/machine-id.Add request middleware that copies the optional
workshop-instance-idheader into the request context, and apply it to the workshopctl endpoint.This change only propagates workshop identity. Validation of the supplied instance ID will be added separately.
LXD integration test identity
Update the LXD integration fixture to use the test runner's numeric UID and GID rather than assuming both are
1000. Workshop instance configuration uses these values inraw.idmapto map the owning host user to the fixed workshop user inside the container.The previous fixture worked only on hosts where the test runner happened to use UID and GID
1000. On other hosts, those IDs can belong to different accounts or groups, causing LXD container creation to fail withoperation not permitted. Usinguser.Current()makes the mapping represent the user actually running the test while retaining the synthetictestusername and isolated LXD project. This is a test portability fix and does not change production identity handling.Testing
go test ./internal/workshop/fakebackend ./internal/workshop/lxd ./internal/overlord/workshopstatego test ./internal/daemon -check.f TestWithWorkshopInstanceIDgo test -v -tags integration ./internal/workshop/lxd/tests/integration -check.v -check.f TestLxdBackendWorkshopInstanceIDDocs