feat(scaffolder): add create-tenant-chart software template#132
Open
quiiver wants to merge 24 commits into
Open
feat(scaffolder): add create-tenant-chart software template#132quiiver wants to merge 24 commits into
quiiver wants to merge 24 commits into
Conversation
Add mozcloud:tenant:read, a pure parseTenantContext(yamlText) that extracts the tenant function and unique realm environment names, wrapped in a zod-based createReadTenantAction() that also derives copierEnvironments (intersection with dev/stage/prod, falling back to all three).
Add run:copier, a scaffolder action that execs the copier CLI in chart mode: writes a --data-file (kind=chart, name, function, environments) to the workspace, injects the GitHub token into the HTTPS clone URL, and streams the run to ctx.logger via executeShellCommand. Register it alongside mozcloud:tenant:read and mozcloud:tenant:add-chart in a new scaffolderModuleMozcloud backend module, and wire that module into the backend.
…overy Adds the Backstage software template that renders a new chart from mozcloud-tenant-skeleton for an existing tenant and opens PRs to both <function>-infra and global-platform-admin, and enables Template discovery (catalog.rules + catalog.locations) so it shows up in the catalog.
The create-tenant-chart scaffolder uses auth.providers.github (requestUserCredentials) to author PRs as the initiator. Document the two env vars: optional locally (provider degrades gracefully in dev), REQUIRED before the app-config block ships to any non-dev environment (the auth backend hard-fails to start without them when NODE_ENV != development).
…nd cwd The catalog FileReaderProcessor globs the location target relative to the backend's process.cwd() (packages/backend under `yarn start`), so `scaffolder-templates/*/template.yaml` matched nothing and the template never appeared under /create. Prefix `../../` to reach the repo root, matching the stock `../../examples/...` convention.
Ships scaffolder-templates/ into the image (/app/scaffolder-templates) so templates can be discovered via a catalog.locations file target in production. The container cwd is /app, so the GKE production config must target `scaffolder-templates/*/template.yaml` (not the `../../` dev path).
Clarify the hybrid GitHub auth model for create-tenant-chart: - Local: set GITHUB_TOKEN=$(gh auth token); the scaffolder falls back to the integration token when no per-user OAuth token is present. - Prod/stage: AUTH_GITHUB_CLIENT_ID/SECRET enable per-user PR authorship via requestUserCredentials.
Add an 'authenticateAsMe' boolean (default true) that gates the RepoUrlPicker behind a schema dependency. When on (stage/prod), the picker mounts and requestUserCredentials runs the OAuth popup for per-user PR authorship. When off (local dev, where no GitHub OAuth provider is configured), the picker never mounts so no popup fires; USER_OAUTH_TOKEN stays empty and the GitHub steps fall back to the backend integration token.
…angs on auth The run:copier action passed the (possibly empty) per-user token straight into the clone URL, so with no USER_OAUTH_TOKEN (local dev) it cloned the private mozcloud-tenant-skeleton unauthenticated and git blocked forever on an interactive credential prompt. - Resolve the clone token via the GitHub integration credential provider when no explicit token is given (mirrors fetch:plain:file / publish:github), extracted as testable resolveCloneToken(). - Set GIT_TERMINAL_PROMPT=0 / GCM_INTERACTIVE=never so a missing/invalid credential fails fast instead of hanging. - Inject DefaultGithubCredentialsProvider via the module (rootConfig).
… as git copier only treats a source as git when the URL starts with a known prefix (incl. https://github.com/) or ends in .git. Injecting x-access-token userinfo breaks the https://github.com/ prefix match, so copier treated the URL as a local path and failed with 'Local template must be a directory.'. Append .git (via ensureGitUrl) so the authed URL stays in git mode.
…es; restore Create nav; drop create-rfc - PR branch names prefixed with the initiating user's local name (e.g. wstuckey-create-chart-<tenant>) via user.entity.metadata.name. - PR titles follow conventional commits: feat(<tenant>): add/register <chart>. - Restore the 'Create...' sidebar item (AddCircleOutline icon). - Remove the create-rfc scaffolder template.
Key branches on user + tenant + chart so adding multiple charts to the same tenant no longer collides on a shared branch name.
Review fixes: - Add git to the backend image apt install. copier shells out to git to clone the template repo, and node:20-bookworm-slim does not ship it, so run:copier would fail at clone time in production. - redactingLogger.child() now wraps the child logger too, so secret redaction can't be bypassed via .child(); add unit tests for the redaction paths.
copier records its source URL verbatim as _src_path in the committed .copier-answers.yml, so injecting the token into the clone URL leaked it into the generated PR. Authenticate the clone via an http.extraheader (GIT_CONFIG_* env, github.com-scoped) with a bare URL instead, so no credential is ever written to disk. Replaces injectToken with buildGitAuthEnv; adds a regression test asserting the clone URL never contains a credential.
…dard
The add-chart action emitted `^<env>-.{40}$` (old 40-char, env-prefixed scheme).
Per Confluence 'Standards: Container Images' + WT-1419, paved-path tags are a
10-char short SHA on main pushes and a semver tag on releases. Emit
`^[0-9a-f]{10}$` for non-prod envs (track main) and `^v[0-9]+\.[0-9]+\.[0-9]+$`
for prod (track release tags), via imageRegexForEnv().
…ged in The chart entry is now authored in the tenant YAML's own schema in scaffolder-templates/create-tenant-chart/chart-values.yaml.njk (globals.deployment.charts.<chart> and realms.<realm>.environments[].charts.<chart>). The mozcloud:tenant:add-chart action renders it with Nunjucks against the tenant's realms — each environment carrying its paved-path image_regex — and drops the generated entries onto the matching tenant paths (comment-preserving round-trip). A fetch:plain:file step stages the template into the workspace.
…token resolution New github:ensureAuth action resolves the effective GitHub credential (per-user token, else the integration credential) and verifies read access to the target repos via the GitHub API, failing early with a clear message (401/403/404) instead of deep in copier/publish. Token resolution (resolveGithubToken) + owner/repo parsing move to a shared module reused by run:copier. The template runs ensure-auth after reading the tenant, before cloning/PRs.
…picker Replace the RepoUrlPicker + authenticateAsMe toggle with a frontend form decorator (packages/app overrides/scaffolder.tsx, registered via FormDecoratorBlueprint). On submit it calls githubAuthApi.getAccessToken — initiating GitHub sign-in if needed — and stashes the token as secrets.USER_OAUTH_TOKEN; when no GitHub provider is configured (local dev) it swallows the error so the steps fall back to the integration token. The template opts in via spec.formDecorators. github:ensureAuth still guards access.
…ution The form decorator now handles obtaining the per-user token, so the github:ensureAuth preflight guard is removed (action, template step, tests). resolveGithubToken (the integration-token fallback used by run:copier) moves back into runCopier.ts as its sole consumer. Trade-off: an access problem now surfaces in the copier/publish step rather than in an early preflight check.
…l popup) The form decorator now only calls getAccessToken (which opens the sign-in popup) when scaffolder.githubUserAuth is set — configured in stage/prod, left unset locally. Locally the decorator returns early, so no popup appears and the backend falls back to the integration token; in prod it prompts for the per-user token. Adds the frontend config schema (packages/app/config.d.ts).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a
create-tenant-chartBackstage software template plus a backend scaffolder module (@internal/plugin-scaffolder-backend-module-mozcloud) that adds a new Helm chart to an existing tenant. For a selected tenant (System) it:mozilla/global-platform-admin.function+ environments (mozcloud:tenant:read).mozilla/mozcloud-tenant-skeletonvia the copier CLI (run:copier, chart mode).<function>-infrawith the rendered chart.mozcloud:tenant:add-chart) and opens a PR toglobal-platform-admin.Key components
plugins/scaffolder-backend-module-mozcloud— three custom actions (mozcloud:tenant:read,run:copier,mozcloud:tenant:add-chart) with pure, unit-tested cores (26 tests). Registered on the scaffolder viacoreServices.rootConfig→ScmIntegrations→DefaultGithubCredentialsProvider.scaffolder-templates/create-tenant-chart/template.yaml— the template. PR branches are keyed<user>-<tenant>-<chart>; PR titles follow conventional commits (feat(<tenant>): …).app-config.yamladdsTemplatetocatalog.rulesand a../../scaffolder-templates/*/template.yamlfile location (relative to the backend cwd inyarn start).packages/backend/requirements.txt(venv at/opt/pyenv),gitinstalled (copier shells out to it), andscaffolder-templates/bundled in.create-rfctemplate.GitHub auth model
requestUserCredentialsis inert and all GitHub steps fall back to the integration token (GITHUB_TOKEN=$(gh auth token)). The template's "Open the PRs as me" toggle lets you skip the OAuth prompt locally.USER_OAUTH_TOKENso PRs are authored by the initiator.Deploy prerequisites (must be done before this works in stage/prod)
catalog.locationsoverride in GKE config — the container cwd is/app, so the prod config must targetscaffolder-templates/*/template.yaml(not the../../dev path). Templates are bundled in the image.auth.providers.github.productionwithAUTH_GITHUB_CLIENT_ID/SECRET. Note themoz-backstage-appGitHub App is currently read-only; per-user PR creation requires it to havecontents: write+pull_requests: write.Testing
.gitURL/credential fallback, log redaction).yarn tsc,yarn lint,yarn prettier:checkclean.Out of scope
app_codeas the chart name rather than the tenant name; fixing that is amozcloud-tenant-skeletonchange, intentionally deferred.