authz-bridge: first end-to-end (hand-written scaffold + factory entry) #9

Open
opened 2026-09-22 19:41:48 +00:00 by ginjiruu · 3 comments
Owner

What to build

The complete end-to-end repo-declared CI chain for lab/authz-bridge, hand-written as the reference shape the onboarding generators (#10) will copy:

  1. Scaffold PR into the authz-bridge repo: a .ci/ directory with a kustomization (common label ci/repo: lab-authz-bridge — K8s label values cannot contain /) and a repo-prefixed tag-build sensor that filters the shared webhook events by repo name and submits go-build-push with params from the event. No k8s/ starter — authz-bridge is a system service deployed by Flux from deployments/kustomization/ (lab/clusters); the app-manifest-location mechanism (per-repo ApplicationSet + repo-declared .ci/apps.yaml) is scoped to #10.
  2. Factory PR into lab/dev-apps-source (two paths — AppProjects must live in the control-plane namespace, see the note on #8):
    • repos/lab-authz-bridge/: a CI Application: source = the authz-bridge repo, path .ci/, destination = mini / ci namespace, destination service account, automated sync (prune + selfHeal), allowEmpty: false; no app Application — authz-bridge has no workloads.
    • projects/lab-authz-bridge.yaml: an AppProject scoped to that repo (sourceRepos = the authz-bridge repo, sourceNamespaces: [dev-apps-source], destinations = mini / ci, destinationServiceAccounts = ci-argocd for mini/ci) with a project role granting the repo owner get/sync/update on the project's applications (app-scoped object form). Correction: Argo CD v3.5.2 has no appRBAC field (verified against the live CRD, the v3.5.x/v3.6 sources, and GitHub) — project roles (spec.roles with proj:<project>:<role> policies) are the per-app RBAC mechanism; edit is not a valid action, update is the edit-equivalent.
  3. Wiring (lab/clusters): a second Kustomization syncing the factory repo's projects/ path into the argocd namespace (Argo CD v3.5.2 only watches AppProjects in the control-plane namespace). The existing dev-apps-source Kustomization continues to sync repos/ into dev-apps-source.
  4. Central allowlist (lab/automation): remove lab/authz-bridge from the central tag-build sensor's allowlist so only the repo's sensor fires on its tag pushes — sensor consumer groups are independent per sensor, so without this both sensors would build. #11 retires the central sensor entirely.

Acceptance criteria

  • All PRs merged (scaffold by the repo maintainer, factory by the user)
  • The CI Application is Synced/Healthy in Argo CD; the sensor and template exist in the ci namespace
  • Pushing a new tag to authz-bridge triggers the repo's sensor (not the central one) and a go-build-push workflow runs
  • A multi-arch image is pushed to Harbor under the new tag
  • The repo owner can view and sync the application in the Argo CD UI (project role verified); a user without the role binding cannot see it

Blocked by

  • None — #7 and #8 are closed
## What to build The complete end-to-end repo-declared CI chain for `lab/authz-bridge`, hand-written as the reference shape the onboarding generators (#10) will copy: 1. **Scaffold PR into the authz-bridge repo**: a `.ci/` directory with a kustomization (common label `ci/repo: lab-authz-bridge` — K8s label values cannot contain `/`) and a repo-prefixed tag-build sensor that filters the shared webhook events by repo name and submits `go-build-push` with params from the event. No `k8s/` starter — authz-bridge is a system service deployed by Flux from `deployments/kustomization/` (lab/clusters); the app-manifest-location mechanism (per-repo ApplicationSet + repo-declared `.ci/apps.yaml`) is scoped to #10. 2. **Factory PR into `lab/dev-apps-source`** (two paths — AppProjects must live in the control-plane namespace, see the note on #8): - `repos/lab-authz-bridge/`: a CI Application: source = the authz-bridge repo, path `.ci/`, destination = mini / `ci` namespace, destination service account, automated sync (prune + selfHeal), `allowEmpty: false`; no app Application — authz-bridge has no workloads. - `projects/lab-authz-bridge.yaml`: an AppProject scoped to that repo (sourceRepos = the authz-bridge repo, `sourceNamespaces: [dev-apps-source]`, destinations = mini / `ci`, destinationServiceAccounts = `ci-argocd` for mini/`ci`) with a **project role** granting the repo owner `get`/`sync`/`update` on the project's `applications` (app-scoped object form). Correction: Argo CD v3.5.2 has no `appRBAC` field (verified against the live CRD, the v3.5.x/v3.6 sources, and GitHub) — project roles (`spec.roles` with `proj:<project>:<role>` policies) are the per-app RBAC mechanism; `edit` is not a valid action, `update` is the edit-equivalent. 3. **Wiring (lab/clusters)**: a second Kustomization syncing the factory repo's `projects/` path into the `argocd` namespace (Argo CD v3.5.2 only watches AppProjects in the control-plane namespace). The existing `dev-apps-source` Kustomization continues to sync `repos/` into `dev-apps-source`. 4. **Central allowlist (lab/automation)**: remove `lab/authz-bridge` from the central tag-build sensor's allowlist so only the repo's sensor fires on its tag pushes — sensor consumer groups are independent per sensor, so without this both sensors would build. #11 retires the central sensor entirely. ## Acceptance criteria - [ ] All PRs merged (scaffold by the repo maintainer, factory by the user) - [ ] The CI Application is Synced/Healthy in Argo CD; the sensor and template exist in the `ci` namespace - [ ] Pushing a new tag to authz-bridge triggers the repo's sensor (not the central one) and a `go-build-push` workflow runs - [ ] A multi-arch image is pushed to Harbor under the new tag - [ ] The repo owner can view and sync the application in the Argo CD UI (project role verified); a user without the role binding cannot see it ## Blocked by - None — #7 and #8 are closed
Author
Owner

Implementation note (verified against argo-cd v3.5.2 source — the version running on portable):

application.namespaces extends only the Application informer. The AppProject informer stays scoped to the control-plane namespace:

  • controller/appcontroller.go:233NewAppProjectInformer(applicationClientset, namespace, ...) (the controller's own namespace)
  • project lookup: GetAppProjectByName(..., ctrl.namespace, ...)projLister.AppProjects(ns).Get(name)

Implication for the factory design (#9): per-repo AppProject objects committed to the factory repo's repos/ path would be synced into the dev-apps-source namespace (the Kustomization's targetNamespace), where Argo CD does not see them. #9 needs either:

  1. per-repo AppProjects placed in the argocd namespace — e.g. a second factory path (e.g. projects/) with a second Kustomization targeting argocd; or
  2. drop per-repo AppProjects and use a shared project (e.g. lab-apps) with per-repo appRBAC rules.

No impact on #8's acceptance criteria (the smoke Application references lab-apps in argocd).

PRs: lab/clusters#1625 (wiring + application.namespaces: *), lab/dev-apps-source#7 (fossil removal + smoke manifests).

Implementation note (verified against argo-cd v3.5.2 source — the version running on portable): `application.namespaces` extends only the **Application** informer. The **AppProject** informer stays scoped to the control-plane namespace: - `controller/appcontroller.go:233` — `NewAppProjectInformer(applicationClientset, namespace, ...)` (the controller's own namespace) - project lookup: `GetAppProjectByName(..., ctrl.namespace, ...)` → `projLister.AppProjects(ns).Get(name)` **Implication for the factory design (#9):** per-repo AppProject objects committed to the factory repo's `repos/` path would be synced into the `dev-apps-source` namespace (the Kustomization's `targetNamespace`), where Argo CD does not see them. #9 needs either: 1. per-repo AppProjects placed in the `argocd` namespace — e.g. a second factory path (e.g. `projects/`) with a second Kustomization targeting `argocd`; or 2. drop per-repo AppProjects and use a shared project (e.g. `lab-apps`) with per-repo `appRBAC` rules. No impact on #8's acceptance criteria (the smoke Application references `lab-apps` in `argocd`). PRs: lab/clusters#1625 (wiring + `application.namespaces: *`), lab/dev-apps-source#7 (fossil removal + smoke manifests).
Author
Owner

Scaffold PR opened: lab/authz-bridge#62 (branch ci/repo-declared-scaffold)

Scope decisions from discussion, recorded here:

  1. k8s/ starter dropped from the scaffold — authz-bridge is a system service deployed by Flux from deployments/kustomization/ (lab/clusters), has no app Application, and needs no k8s/ directory. The app-manifest-location mechanism (per-repo ApplicationSet + repo-declared .ci/apps.yaml, Git file generator) is drafted into #10's scope.
  2. Label value sanitized: ci/repo: lab-authz-bridge (K8s label values cannot contain '/').
  3. Sensor SA is ci-argocd (the ci-namespace destination SA — only SA in ci with create on workflows).

Scaffold validated: kustomize build clean + server-side dry-run against the live argo-events v1.9.10 Sensor CRD on mini. Cross-namespace event flow (webhook EventSource in automation → sensor in ci) verified against the v1.9.10 source: JetStream subject is default.. with no namespace, shared NATS server, and the sensor reconciler never fetches the EventSource object.

Remaining: factory PR (dev-apps-source) + wiring PR (lab/clusters projects/ → argocd) + central-allowlist removal (automation), then the e2e tag-push test.

Scaffold PR opened: https://git.animeteamspeak.moe/lab/authz-bridge/pulls/62 (branch ci/repo-declared-scaffold) Scope decisions from discussion, recorded here: 1. k8s/ starter dropped from the scaffold — authz-bridge is a system service deployed by Flux from deployments/kustomization/ (lab/clusters), has no app Application, and needs no k8s/ directory. The app-manifest-location mechanism (per-repo ApplicationSet + repo-declared .ci/apps.yaml, Git file generator) is drafted into #10's scope. 2. Label value sanitized: ci/repo: lab-authz-bridge (K8s label values cannot contain '/'). 3. Sensor SA is ci-argocd (the ci-namespace destination SA — only SA in ci with create on workflows). Scaffold validated: kustomize build clean + server-side dry-run against the live argo-events v1.9.10 Sensor CRD on mini. Cross-namespace event flow (webhook EventSource in automation → sensor in ci) verified against the v1.9.10 source: JetStream subject is default.<source>.<event> with no namespace, shared NATS server, and the sensor reconciler never fetches the EventSource object. Remaining: factory PR (dev-apps-source) + wiring PR (lab/clusters projects/ → argocd) + central-allowlist removal (automation), then the e2e tag-push test.
Author
Owner

All four PRs for #9 are open/merged:

PR Repo State
lab/authz-bridge#62 scaffold (.ci/ kustomization + tag-build sensor) merged
lab/dev-apps-source#8 factory entry (CI Application + AppProject) open
lab/clusters#1628 wiring (projects/ → argocd Kustomization) open
lab/automation#15 central allowlist removal open

Spec correction recorded in the issue body: Argo CD v3.5.2 has no appRBAC field (verified against the live CRD, v3.5.x/v3.6 sources, and GitHub) — the AppProject uses a project role (repo-owner) with app-scoped policies granting get/sync/update (edit is not a valid action) on lab-authz-bridge/*, bound to the admin group (the repo owner's claim). Global RBAC is deny-by-default, so the negative test (user without the binding cannot see the app) holds.

Remaining after the three open PRs merge:

  1. E2E tag-push test: push a new tag to authz-bridge → repo sensor (not central) fires → go-build-push runs in ci → multi-arch image in Harbor under the new tag
  2. RBAC verification: repo owner can view/sync in the UI (project role); a user without the binding cannot see the app
All four PRs for #9 are open/merged: | PR | Repo | State | |----|------|-------| | lab/authz-bridge#62 | scaffold (.ci/ kustomization + tag-build sensor) | merged | | lab/dev-apps-source#8 | factory entry (CI Application + AppProject) | open | | lab/clusters#1628 | wiring (projects/ → argocd Kustomization) | open | | lab/automation#15 | central allowlist removal | open | Spec correction recorded in the issue body: Argo CD v3.5.2 has no appRBAC field (verified against the live CRD, v3.5.x/v3.6 sources, and GitHub) — the AppProject uses a project role (repo-owner) with app-scoped policies granting get/sync/update (edit is not a valid action) on lab-authz-bridge/*, bound to the admin group (the repo owner's claim). Global RBAC is deny-by-default, so the negative test (user without the binding cannot see the app) holds. Remaining after the three open PRs merge: 1. E2E tag-push test: push a new tag to authz-bridge → repo sensor (not central) fires → go-build-push runs in ci → multi-arch image in Harbor under the new tag 2. RBAC verification: repo owner can view/sync in the UI (project role); a user without the binding cannot see the app
Sign in to join this conversation.
No labels
ready-for-agent
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lab/automation#9
No description provided.