Azure / Azure/osdu-spi-stack

feat(cli): canonical image source policy and declared forks

Open
#192 0 comments 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
Python
Stars
0
Forks
2
Avg merge
7h 6m
Merged PRs (30d)
107

Description

Part of Borrow, Prove, Restore (Azure/osdu-spi#158), Phase 2. Continues #130, whose trust half shipped in #174 and #179.

## Problem

ADR-032 and ADR-033 describe a source policy and a declaration format that the code does not have. `spi onboard` trusts a repository but cannot promote its image to canonical: `--canonical-source` appears nowhere in `src/spi`, no `spi-source-` resource-group tag is written or read, and `spi up` resolves every service from the community registry regardless of trust. The declaration in `src/spi/environment.py` is the flat seven-key schema; it has no `forks:` list, `spi up` takes no `--declaration`, and the refresh and upgrade workflows reconcile nothing from it. Until this lands a fork PR can borrow a slot with an ephemeral pin (#129) but a promoted fork image never becomes the environment's standing source, so Azure/osdu-spi#155 cannot exercise the full path.

## Required change

The decision records are the spec. Read ADR-032 (Declared intent wins, Onboarding plans by default), ADR-033 (Decision), ADR-029 (Identities belong to the lifecycle), and `docs/design/fork-deployment.md` before starting, and implement what they describe rather than redesigning it.

1. **Source policy on the CLI.** `spi onboard --repo / --canonical-source fork|community`. `fork` writes the RG tag `spi-source-=/`; `community` writes `community`; omitting the option preserves the recorded value and defaults a new service to community. The source must equal the trusted repository for that service. Tag writes merge only the owned tags and preserve `spi-name-suffix`, the declaration locator, and unrelated tags. `--list` shows the source beside the trusted repository. `--remove` returns the service to community.
2. **Resolution honors the source.** `spi up`, `spi reconcile --image-branch`, and the refresh path resolve a service whose source is `/` from `ghcr.io//` at the fork's `main` digest, using the mapping in `images.py` (`fork_package_repository`), and everything else from community. A missing or private package is an error, not a fallback. The lock carries the source alongside the image so `spi info --json` and `spi service list` show where each image came from.
3. **Schema stays gated.** Onboard trusts a repository for `schema` but refuses `--canonical-source fork` until `ghcr.io//schema-load` exists at the selected commit, and the refusal names the missing package. Today `require_known_service` in `onboard.py` rejects schema outright; change that to trust-only.
4. **Declaration `forks:`.** Extend `EnvironmentDeclaration` with an optional `forks` list of `{service, repo, canonicalSource}` (`canonicalSource` defaults to `community`). `repo` unique across the list, `service` known to `IMAGE_REGISTRY`, `forks` invalid with any profile but `core`. `spi up --declaration /:` loads the reviewed file from `main`, records the locator in the RG tag `spi-environment-declaration`, and refuses explicit flags that conflict with it. A later `spi up` without the option reads the retained locator.
5. **Lifecycle reconciliation.** On a declared environment, `spi up` bootstrap and the refresh path reconcile the deploy identity's federated credentials and the source tags to `forks:` before projecting into the lock, serially per identity with the backoff ADR-032 requires. `spi onboard` on a declared environment refuses an addition, removal, repository change, or source choice that disagrees with the declaration and says which file to change.
6. **Docs.** `docs/design/fork-deployment.md` gets the `--canonical-source` mechanics and a `forks:` example; `docs/design/environment-lifecycle.md` gets the reconcile order. ADRs need no change unless the implementation deviates; if it must, amend the record in the same PR and say why. No em dashes; follow `docs/STYLE.md`.

## Acceptance

- `spi onboard partition --repo / --write --canonical-source fork` leaves `spi-source-partition=/` on the resource group and the next `spi reconcile --image-branch master` pins partition to a `ghcr.io//partition@sha256:` digest; `--canonical-source community` returns it to `community.opengroup.org` on the next reconcile with the credential still present.
- `spi onboard schema --repo / --write` succeeds; adding `--canonical-source fork` on a fork with no `schema-load` package exits nonzero naming `ghcr.io//schema-load`.
- A declaration with `forks:` and `profile: minimal` fails validation; a duplicate `repo` fails validation; `spi up --declaration` on a fresh environment records the locator and leaves credentials and source tags matching the file.
- `spi onboard` against a declared environment refuses an undeclared repository and names the declaration file.
- Unit tests cover the planner rows and steps for each source transition, declaration validation, and resolver selection between community and fork packages, in the style of `tests/test_onboard.py` (canned observed state, no simulated GitHub or Azure).

## Verify

```bash
uv run pre-commit run --all-files
```

Report the result in the PR description. The end-to-end acceptance lines above need a real environment; state in the PR which of them you ran and which a maintainer must run on the shared environment.

## Out of scope

- Entitlements for the fork identity and the no-access test identity (#132).
- The borrow, prove, restore job in the service template (Azure/osdu-spi#155).
- Moving `ops/environments/shared.yaml` to a fork declaration for the shared environment; that is a follow-up PR by a maintainer once this merges.

## Constraints

- Branch: `feat/canonical-source-policy`. Conventional Commits; PR title `feat(cli): canonical image source policy and declared forks`. Split into two PRs (source policy, then declarations) if the first passes 1500 changed lines.
- Do not merge, do not force-push, no generated-with footers or co-author trailers on commits or the PR.
- PR description follows the shape in `CONTRIBUTING.md`.

Contributor guide

Open the contributing guide

Research direction

Start with ADR-032, ADR-033, ADR-029, and docs/design/fork-deployment.md, then inspect src/spi/environment.py, images.py, and onboard.py alongside tests/test_onboard.py. Run the stated pre-commit command and use the acceptance cases to verify source transitions, declaration validation, resolver selection, and lifecycle reconciliation; real-environment checks must be reported separately for maintainers.

Written by the indexing model from the issue text.

Assessment

Tech stack
azure, github, python
Domain
cli, cloud, devops
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.