MirroredImage Specification
Boundary
| Concern |
Requirement |
| Controller |
A dedicated controller Deployment and service account watch MirroredImage; the Project Delivery controller does not. |
| Isolation |
Mirrored Image and Project Delivery controller pods remain separate because their permissions and owned resources differ. |
| Reuse |
Generic Go libraries and the F# runner may be shared; controller state machines remain separate. |
| Intent |
One MirroredImage owns one upstream repository. |
| Destination |
The corresponding Quay repositories are candidates/<metadata.name> and mirror/<metadata.name>. |
| Credentials |
Two Zitadel-backed Quay personas isolate OAuth authority by organization; four assigned tokens isolate it by privilege. |
| New work |
The MirroredImage API, controller state machine, Argo Workflows, and tests are independent work. |
| Excluded input |
Smeltery specifications, implementation, workflows, and tests are not inputs. |
| Workload policy |
Workload image-reference policy is outside the controller; Kyverno governs workload declarations. |
Declaration
kind: MirroredImage
metadata:
name: ingress-nginx
spec:
upstream: registry.k8s.io/ingress-nginx/controller
policy:
rejectAtOrAbove: High
digests:
- digest: sha256:...
tag: v1.13.0
- digest: sha256:...
Quay authorization
OAuth application scopes are privilege boundaries, not organization boundaries. Each token acts as its assigned persona, and each persona has Quay authority only within its corresponding organization.
| Persona |
Quay resource boundary |
Token |
OAuth scope |
mirror-bot |
mirror only |
mirror-reader |
repo:read |
mirror-bot |
mirror only |
mirror-writer |
repo:create, repo:write |
candidates-bot |
candidates only |
candidates-reader |
repo:read |
candidates-bot |
candidates only |
candidates-writer |
repo:create, repo:write |
The reader and writer tokens are distinct credentials despite being assigned to the same persona. Neither persona has Quay authority in quorate or in the other mirror organization.
Quay treats repo:write as including repo:read; each writer token therefore has create, read, and write authority inside its persona's organization.
| Runtime |
Quay credentials |
| Controller |
candidates-reader, mirror-reader |
| Prepare Workflow |
candidates-writer |
| Promote Workflow |
candidates-reader, mirror-writer |
| Candidate GC |
candidates-writer |
| Mirror GC |
mirror-writer |
Models
Workflow interface
| Argo Workflow |
Stages |
| Prepare |
Prepare |
| Promotion |
Promote |
| Cleanup |
Candidate GC, Mirror GC |
| Field |
Type |
retryOf |
Workflow-name reference |
mirror.quorate.dev/retry |
Workflow-name reference |
status.lastHandledRetry |
Workflow-name reference |
Scan inputs
| Image shape |
ClairInputs |
| Single manifest |
Candidate manifest |
| OCI index |
Child manifests |
\mathrm{Safe} \iff \forall m \in \mathrm{ClairInputs}:\ \mathrm{ReportAvailable}(m) \land \forall v \in \mathrm{Findings}(m):\ \mathrm{severity}(v) < \mathrm{spec.policy.rejectAtOrAbove}