Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/cli/repos.md
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ If tag-to-SHA resolution fails (e.g. the tag does not exist or the API is unreac

## `repos upgrade-mint`

Verifies the token mint Cloud Function matches the manifest configuration. Discovers the current mint deployment and checks that its URL matches the manifest's `mint.url`.
Verifies the token mint Cloud Function matches the manifest configuration. Discovers the current mint deployment and checks that its URL matches the manifest's `forge.github.mint_url`.

`repos upgrade` now runs mint verification automatically as a pre-flight check. This command remains available for standalone verification without triggering an upgrade.

Expand Down
9 changes: 5 additions & 4 deletions docs/guides/getting-started/repo-management.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,11 @@ entry. Per-repo overrides are supported for mixed-forge manifests:

```yaml
version: 1
mint:
url: https://mint.example.com
project: my-project
region: us-central1
forge:
github:
mint_url: https://mint.example.com
mint_project: my-project
mint_region: us-central1
defaults:
forge: github
fullsend_ref: v2.5.0
Expand Down
14 changes: 7 additions & 7 deletions docs/plans/repos-init.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ Flags:
include. Skips interactive selection.
- `--all` (bool): include all eligible repos without prompting.
- `--forge` (string, **required**): forge type (`github` or `gitlab`).
- `--mint-project` (string): GCP project for the `mint.project` field.
- `--mint-project` (string): GCP project for the `forge.github.mint_project` field.
- `--mint-region` (string, default `us-central1`): GCP region for
the `mint.region` field.
the `forge.github.mint_region` field.
- `--inference-project` (string): default GCP project for inference.
- `--concurrency` (int, default 8): max parallel API calls.

Expand Down Expand Up @@ -201,15 +201,15 @@ func buildManifest(repos []DiscoveredRepo,
cfg InitConfig) (*Manifest, []string)
```

1. **Compute `mint:` block:**
- `url`: from discovered `FULLSEND_MINT_URL` (should be uniform
1. **Compute `forge.github:` block** (only when `--forge=github`):
- `mint_url`: from discovered `FULLSEND_MINT_URL` (should be uniform
across repos sharing a mint). If repos report different mint
URLs, use the most common and add a TODO. For greenfield (no
discovered URLs), leave as TODO (Cloud Run URLs contain a random
hash and cannot be derived from the project name alone).
- `project`: from `--mint-project` flag. If not provided, add to
- `mint_project`: from `--mint-project` flag. If not provided, add to
TODO list.
- `region`: from `--mint-region` flag (default `us-central1`).
- `mint_region`: from `--mint-region` flag (default `us-central1`).

2. **Compute `defaults:` block** by finding the mode (most common
value) for each field across discovered repos. For greenfield
Expand All @@ -233,7 +233,7 @@ func buildManifest(repos []DiscoveredRepo,
- New repos (not yet installed) are included as normal entries.

4. **Return TODO list** for fields that could not be discovered (e.g.,
`inference_project` when no flag provided, `mint.project` when
`inference_project` when no flag provided, `forge.github.mint_project` when
omitted).

**Secret limitation:** `FULLSEND_GCP_PROJECT_ID` and
Expand Down
45 changes: 26 additions & 19 deletions docs/plans/repos-management.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@ The manifest declares desired state for all managed repos:
```yaml
version: 1

# Shared mint infrastructure — one mint serves all repos.
# url: Cloud Run endpoint (contains a random hash, not derivable from project/region).
# project + region: needed for WIF provisioning (IAM bindings), not for addressing the mint.
mint:
url: https://fullsend-mint-abc123-uc.a.run.app
project: acme-fullsend-prod
region: us-central1
# Per-forge infrastructure configuration.
forge:
github:
# Shared mint infrastructure — one mint serves all repos.
# mint_url: Cloud Run endpoint (contains a random hash, not derivable from project/region).
# mint_project + mint_region: needed for WIF provisioning (IAM bindings).
mint_url: https://fullsend-mint-abc123-uc.a.run.app
mint_project: acme-fullsend-prod
mint_region: us-central1

# Default configuration applied to all repos unless overridden.
defaults:
Expand Down Expand Up @@ -78,7 +80,7 @@ Manifest fields map to repo-level resources as follows:
| `inference_project` | `FULLSEND_GCP_PROJECT_ID` | Secret |
| `inference_region` | `FULLSEND_GCP_REGION` | Variable |
| `fullsend_ref` | `@ref` in scaffold shim `uses:` line | Workflow file |
| `mint.url` | `FULLSEND_MINT_URL` | Variable |
| `forge.github.mint_url` | `FULLSEND_MINT_URL` | Variable |
| `base_harness` | `.fullsend/harness.yaml` `base:` field | Config file |
| `allowed_remote_resources` | `allowed_remote_resources` in org `config.yaml` | Config file ¹ |

Expand Down Expand Up @@ -203,7 +205,7 @@ Reconciles configuration drift for installed repos.

| Resource | Action |
|----------|--------|
| `FULLSEND_MINT_URL` variable | Upsert to match manifest `mint.url` |
| `FULLSEND_MINT_URL` variable | Upsert to match manifest `forge.github.mint_url` |
| `FULLSEND_GCP_REGION` variable | Upsert to match resolved `inference_region` |
| `FULLSEND_GCP_PROJECT_ID` secret | Upsert to match resolved `inference_project` |

Expand Down Expand Up @@ -245,7 +247,7 @@ rather than falling back to tag-only format.

Verifies the token mint deployment matches the manifest configuration.
Discovers the current mint via `DiscoverMint` and checks that its URL
matches `mint.url`. `repos upgrade` now runs this check automatically
matches `forge.github.mint_url`. `repos upgrade` now runs this check automatically
as a pre-flight step (unless `--skip-mint-check` is set); this command
remains available for standalone verification.

Expand Down Expand Up @@ -487,15 +489,20 @@ Unit tests with fakes. Run `make go-test` to verify no regressions in
```go
type Manifest struct {
Version int `yaml:"version"`
Mint MintConfig `yaml:"mint"`
Forge ForgeSection `yaml:"forge"`
Defaults DefaultsConfig `yaml:"defaults"`
Repos []RepoEntry `yaml:"repos"`
}

type MintConfig struct {
URL string `yaml:"url"`
Project string `yaml:"project"`
Region string `yaml:"region"`
type ForgeSection struct {
GitHub GitHubForgeInfra `yaml:"github,omitempty"`
GitLab GitLabForgeInfra `yaml:"gitlab,omitempty"`
}

type GitHubForgeInfra struct {
MintURL string `yaml:"mint_url,omitempty"`
MintProject string `yaml:"mint_project,omitempty"`
MintRegion string `yaml:"mint_region,omitempty"`
}

type DefaultsConfig struct {
Expand Down Expand Up @@ -589,8 +596,8 @@ the URL fetching logic from the harness resource loader.
`Validate()` checks:

- `version` is 1 (only supported version).
- `mint.url` is a valid HTTPS URL.
- `mint.project` and `mint.region` are non-empty.
- `forge.github.mint_url` is a valid HTTPS URL (when GitHub repos are present).
- `forge.github.mint_project` and `forge.github.mint_region` are non-empty (when GitHub repos are present).
- Each repo entry has a valid `owner/repo` format.
- No duplicate repos (after glob expansion).
- Glob patterns are valid `filepath.Match` patterns with an `org/`
Expand Down Expand Up @@ -1036,7 +1043,7 @@ What sync reconciles:

| Resource | Action |
|----------|--------|
| `FULLSEND_MINT_URL` | Upsert to match `mint.url` |
| `FULLSEND_MINT_URL` | Upsert to match `forge.github.mint_url` |
| `FULLSEND_GCP_REGION` | Upsert to match resolved `inference_region` |
| `FULLSEND_PER_REPO_INSTALL` | Ensure `"true"` |
| `FULLSEND_GCP_PROJECT_ID` | Upsert to match resolved `inference_project` |
Expand Down Expand Up @@ -1176,7 +1183,7 @@ rather than falling back to tag-only format.

- Create provisioner from manifest's mint config.
- Discover the current mint deployment via `DiscoverMint`.
- Verify discovered mint URL matches the manifest's `mint.url`.
- Verify discovered mint URL matches the manifest's `forge.github.mint_url`.

#### `internal/repos/upgrade_test.go` (new)

Expand Down
36 changes: 25 additions & 11 deletions internal/cli/repos.go
Original file line number Diff line number Diff line change
Expand Up @@ -972,17 +972,20 @@ func confirmBulkAction(printer *ui.Printer, action string, patterns []string, ma
return nil
}

func resolveMintProvisioner(testProv repos.WIFProvisioner, m *repos.Manifest) repos.WIFProvisioner {
func resolveMintProvisioner(testProv repos.WIFProvisioner, m *repos.Manifest) (repos.WIFProvisioner, error) {
if testProv != nil {
return testProv
return testProv, nil
}
if m.Forge.GitHub.MintProject == "" {
return nil, fmt.Errorf("resolveMintProvisioner requires GitHub forge config (mint_project); guard with m.HasForge(repos.ForgeGitHub)")
}
return &gcfProvisionerAdapter{
provisioner: gcf.NewProvisioner(gcf.Config{
ProjectID: m.Mint.Project,
Region: m.Mint.Region,
MintURL: m.Mint.URL,
}, gcf.NewLiveGCFClient(m.Mint.Project)),
}
ProjectID: m.Forge.GitHub.MintProject,
Region: m.Forge.GitHub.MintRegion,
MintURL: m.Forge.GitHub.MintURL,
}, gcf.NewLiveGCFClient(m.Forge.GitHub.MintProject)),
}, nil
}

// buildProvisionerFactory creates a ProvisionerFactory for uninstall operations.
Expand Down Expand Up @@ -1339,10 +1342,13 @@ func runReposUpgrade(ctx context.Context, opts *reposUpgradeConfig, repoFilter [
return err
}

if !opts.skipMintCheck {
if !opts.skipMintCheck && m.HasForge(repos.ForgeGitHub) {
printer.StepStart("Verifying mint deployment")

provisioner := resolveMintProvisioner(opts.testProvisioner, m)
provisioner, err := resolveMintProvisioner(opts.testProvisioner, m)
if err != nil {
return err
}

mintProgressFn := func(repo, phase, msg string) {
printer.StepInfo(fmt.Sprintf("[%s] %s", repo, msg))
Expand Down Expand Up @@ -1450,7 +1456,7 @@ func newReposUpgradeMintCmd() *cobra.Command {
Long: `Verifies the token mint Cloud Function matches the manifest configuration.

Discovers the current mint deployment and checks that its URL matches
the manifest's mint.url. This check runs automatically as a pre-flight
the manifest's forge.github.mint_url. This check runs automatically as a pre-flight
step in 'repos upgrade'; this command is available for standalone
verification without triggering an upgrade.`,
RunE: func(cmd *cobra.Command, args []string) error {
Expand All @@ -1476,7 +1482,15 @@ func runReposUpgradeMint(ctx context.Context, opts *reposUpgradeMintConfig) erro
}
printer.StepDone("Loaded manifest")

provisioner := resolveMintProvisioner(opts.testProvisioner, m)
if !m.HasForge(repos.ForgeGitHub) {
printer.StepDone("No GitHub repos in manifest — skipping mint verification")
return nil
}

provisioner, err := resolveMintProvisioner(opts.testProvisioner, m)
if err != nil {
return err
}

progressFn := func(repo, phase, msg string) {
printer.StepInfo(fmt.Sprintf("[%s] %s", repo, msg))
Expand Down
Loading
Loading