From b10d33f7ae69a3e3f75e5dca62110a6f3e2ae4d3 Mon Sep 17 00:00:00 2001 From: Isaac Karrer Date: Mon, 26 Oct 2026 17:00:11 -0500 Subject: [PATCH 1/2] Rename to declaration-check; catalog belongs to the Flox Catalog "Catalog" is a product term here. floxhub alone holds catalog-server, catalog-common, catalog-publisher and catalog-updater, and the Flox Catalog is the capital-C thing all of them serve. A compliance checker borrowing the word makes every one of those harder to search for and harder to reason about, which is a cost paid by people who have nothing to do with this repository. The name came from the file it reads, catalog-info.yaml, which was locally descriptive and globally wrong. declaration-check names what it validates and matches vocabulary already in use: declaration.py holds the parser, and the check engineers see in their pull requests is already "declaration is complete". The repository id is unchanged, so the organisation ruleset that requires this workflow follows the rename without edits, and GitHub redirects the old path for anything not yet updated. catalog-info.yaml itself is untouched. That filename is Backstage's convention rather than ours, and interoperating with it is why ADR-001 chose the format. Co-Authored-By: Claude Opus 5 --- .flox/env.json | 2 +- .github/actions/check/action.yml | 2 +- .../workflows/{catalog-check.yml => declaration-check.yml} | 4 ++-- .github/workflows/tests.yml | 2 +- README.md | 6 +++--- catalog-info.yaml | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) rename .github/workflows/{catalog-check.yml => declaration-check.yml} (89%) diff --git a/.flox/env.json b/.flox/env.json index 4a42555..2e3356b 100644 --- a/.flox/env.json +++ b/.flox/env.json @@ -1,5 +1,5 @@ { - "name": "catalog-check", + "name": "declaration-check", "version": 1, "env_id": "47ab46d7-8fac-4adf-8615-34b14a0cc0c6" } diff --git a/.github/actions/check/action.yml b/.github/actions/check/action.yml index f06f4f8..3ed9533 100644 --- a/.github/actions/check/action.yml +++ b/.github/actions/check/action.yml @@ -12,7 +12,7 @@ # A composite action rather than a reusable workflow for the checks themselves: # GitHub fetches an action's source while resolving `uses:`, so a caller needs # nothing checked out but its own repository. -name: catalog-check +name: declaration-check description: Run one of the checks every flox repository must pass. inputs: diff --git a/.github/workflows/catalog-check.yml b/.github/workflows/declaration-check.yml similarity index 89% rename from .github/workflows/catalog-check.yml rename to .github/workflows/declaration-check.yml index 232de76..e135b22 100644 --- a/.github/workflows/catalog-check.yml +++ b/.github/workflows/declaration-check.yml @@ -10,7 +10,7 @@ # would reach private repositories only, and 83 of the live ones are public. # # Nothing here reads a credential, and nothing here needs to. See the action. -name: catalog-check +name: declaration-check on: # Kept callable directly so a repository can adopt the check ahead of the @@ -33,7 +33,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - - uses: flox/catalog-check/.github/actions/check@2f04631c4c19ac18270d6589c8b6bf8ddbbfb504 # keep in step with main + - uses: flox/declaration-check/.github/actions/check@2f04631c4c19ac18270d6589c8b6bf8ddbbfb504 # keep in step with main with: check: declaration path: ${{ inputs.path || 'catalog-info.yaml' }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9277b79..df084f4 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,6 +1,6 @@ # This repository's own unit tests. Nothing else runs them, and no other # repository cares about them — the check other repositories must pass is in -# catalog-check.yml. +# declaration-check.yml. name: tests # No paths filter, deliberately. A required check that is skipped never reports, diff --git a/README.md b/README.md index 7d1546f..e2141b8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# catalog-check +# declaration-check Checks that a flox repository declares what it is and who owns it. @@ -12,7 +12,7 @@ check that the declaration is present and complete, and nothing else. apiVersion: backstage.io/v1alpha1 kind: Component metadata: - name: catalog-check + name: declaration-check labels: flox.dev/classification: internal-tooling # customer-facing | distribution | internal-tooling | non-shipping | non-production flox.dev/max-tier: manual # auto | assisted | manual @@ -31,7 +31,7 @@ else notices. ## Running it -An organisation ruleset names `.github/workflows/catalog-check.yml` as a required +An organisation ruleset names `.github/workflows/declaration-check.yml` as a required workflow, so repositories do not call it themselves. To run it against a checkout: ``` diff --git a/catalog-info.yaml b/catalog-info.yaml index d3b0c29..e09226b 100644 --- a/catalog-info.yaml +++ b/catalog-info.yaml @@ -1,7 +1,7 @@ apiVersion: backstage.io/v1alpha1 kind: Component metadata: - name: catalog-check + name: declaration-check description: The check that every flox repository declares what it is and who owns it. labels: flox.dev/classification: internal-tooling From 51a2baae614d54efcabd67be9a9de261c8ba837b Mon Sep 17 00:00:00 2001 From: Isaac Karrer Date: Mon, 26 Oct 2026 17:03:09 -0500 Subject: [PATCH 2/2] Call the declaration flox-info.yaml; the schema stays Backstage's MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backstage's convention is catalog-info.yaml, and "catalog" at flox means the Flox Catalog — the capital-C thing that catalog-server, catalog-common, catalog-publisher and catalog-updater all serve. A file in all 176 repositories borrowing that word costs more in confusion than the default filename saves in configuration, and the cost lands on people with no stake in this process. Only the name changes. The contents remain a Backstage entity descriptor, unchanged, so a Backstage instance could still read them — the schema is the part worth having and the reason ADR-001 chose the format. Backstage's catalog accepts a configured filename, so the interop that matters survives. Renaming now because the cost only grows: three repositories carry the file today and the backfill in OPS-127 takes it to 176. Co-Authored-By: Claude Opus 5 --- .github/actions/check/action.yml | 2 +- .github/workflows/declaration-check.yml | 4 ++-- README.md | 19 +++++++++++++------ declaration.py | 8 +++++--- catalog-info.yaml => flox-info.yaml | 0 test_declaration.py | 24 ++++++++++++------------ 6 files changed, 33 insertions(+), 24 deletions(-) rename catalog-info.yaml => flox-info.yaml (100%) diff --git a/.github/actions/check/action.yml b/.github/actions/check/action.yml index 3ed9533..2262af2 100644 --- a/.github/actions/check/action.yml +++ b/.github/actions/check/action.yml @@ -23,7 +23,7 @@ inputs: path: description: Declaration to read, relative to the repository root. required: false - default: catalog-info.yaml + default: flox-info.yaml python-version: required: false default: '3.12' diff --git a/.github/workflows/declaration-check.yml b/.github/workflows/declaration-check.yml index e135b22..f81a002 100644 --- a/.github/workflows/declaration-check.yml +++ b/.github/workflows/declaration-check.yml @@ -19,7 +19,7 @@ on: inputs: path: type: string - default: catalog-info.yaml + default: flox-info.yaml pull_request: push: branches: [main] @@ -36,4 +36,4 @@ jobs: - uses: flox/declaration-check/.github/actions/check@2f04631c4c19ac18270d6589c8b6bf8ddbbfb504 # keep in step with main with: check: declaration - path: ${{ inputs.path || 'catalog-info.yaml' }} + path: ${{ inputs.path || 'flox-info.yaml' }} diff --git a/README.md b/README.md index e2141b8..5ffeee0 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,18 @@ Checks that a flox repository declares what it is and who owns it. -Every repository carries a `catalog-info.yaml` — a [Backstage entity -descriptor](https://backstage.io/docs/features/software-catalog/descriptor-format) -— saying how exposed it is, how much human review a dependency bump needs, its -maturity, and which area of responsibility owns it. This repository holds the -check that the declaration is present and complete, and nothing else. +Every repository carries a `flox-info.yaml` saying how exposed it is, how much +human review a dependency bump needs, its maturity, and which area of +responsibility owns it. This repository holds the check that the declaration is +present and complete, and nothing else. + +The contents are a [Backstage entity +descriptor](https://backstage.io/docs/features/software-catalog/descriptor-format), +unchanged — the schema is theirs and worth keeping, so a Backstage instance could +read these as-is. Only the filename is ours. Backstage's own convention is +`catalog-info.yaml`, and "catalog" at flox means the Flox Catalog, which several +floxhub components serve; a file in every repository borrowing that word would +cost more in confusion than the default filename saves in configuration. ```yaml apiVersion: backstage.io/v1alpha1 @@ -35,7 +42,7 @@ An organisation ruleset names `.github/workflows/declaration-check.yml` as a req workflow, so repositories do not call it themselves. To run it against a checkout: ``` -python3 declaration.py --path catalog-info.yaml +python3 declaration.py --path flox-info.yaml ``` It exits 0 when the declaration is complete, 1 with the fields that are missing or diff --git a/declaration.py b/declaration.py index 780a440..faa8f15 100644 --- a/declaration.py +++ b/declaration.py @@ -5,7 +5,9 @@ place that knows the format: everything downstream takes the dict this returns, so changing the encoding later means changing this file and nothing else. -Today the encoding is a Backstage entity descriptor at `catalog-info.yaml`. That +Today the encoding is a Backstage entity descriptor at `flox-info.yaml` — their +schema, our filename, because `catalog-info.yaml` would put the Flox Catalog's +word in every repository. That is an implementation detail, not a commitment — see ADR-001 and ADR-008's withdrawal. Backstage's own schema validates the envelope; it does not validate our facts, because `metadata.labels` is an open string map and will accept a @@ -383,7 +385,7 @@ def is_expected_in_production(decl, today=None): # explains why it is being asked. # --------------------------------------------------------------------------- -DEFAULT_PATH = "catalog-info.yaml" +DEFAULT_PATH = "flox-info.yaml" TEMPLATE = """apiVersion: backstage.io/v1alpha1 kind: Component @@ -487,7 +489,7 @@ def _report_uncovered(args, gaps, declared): "declared, because its %d other part%s %s." % (declared, "" if declared == 1 else "s", "is" if declared == 1 else "are"), file=out) - print("\nAdd a catalog-info.yaml in each, and list it in %s. Or, if one of the " + print("\nAdd a flox-info.yaml in each, and list it in %s. Or, if one of the " "parts already declared should own it, move that declaration up to the " "directory above both." % args.path, file=out) _write_summary(args, "### Undeclared parts\n\n%s\n" diff --git a/catalog-info.yaml b/flox-info.yaml similarity index 100% rename from catalog-info.yaml rename to flox-info.yaml diff --git a/test_declaration.py b/test_declaration.py index 74dea27..f4cc4f6 100644 --- a/test_declaration.py +++ b/test_declaration.py @@ -173,14 +173,14 @@ class TestMonorepoLocations(unittest.TestCase): " name: example\n" "spec:\n" " targets:\n" - " - ./src/web-ui/catalog-info.yaml\n" - " - ./src/web-bff/catalog-info.yaml\n" + " - ./src/web-ui/flox-info.yaml\n" + " - ./src/web-bff/flox-info.yaml\n" ) def test_targets_are_read_and_normalised(self): self.assertEqual( declaration.targets(self.LOCATION), - ["src/web-ui/catalog-info.yaml", "src/web-bff/catalog-info.yaml"]) + ["src/web-ui/flox-info.yaml", "src/web-bff/flox-info.yaml"]) def test_a_component_is_not_a_location(self): self.assertIsNone(declaration.targets(decl())) @@ -200,7 +200,7 @@ def test_a_location_pointing_outside_the_repository_is_refused(self): the property ADR-001 exists to get. """ external = (self.LOCATION.split("targets:")[0] - + "targets:\n - https://example.com/catalog-info.yaml\n") + + "targets:\n - https://example.com/flox-info.yaml\n") with self.assertRaises(declaration.Invalid) as caught: declaration.targets(external) self.assertIn("not URLs", " ".join(caught.exception.problems)) @@ -376,20 +376,20 @@ def location(self, *targets): def test_a_dotted_directory_keeps_its_dot(self): self.assertEqual( - declaration.targets(self.location("./.github/catalog-info.yaml")), - [".github/catalog-info.yaml"]) + declaration.targets(self.location("./.github/flox-info.yaml")), + [".github/flox-info.yaml"]) def test_a_dotted_directory_without_a_prefix_is_unchanged(self): self.assertEqual( - declaration.targets(self.location(".github/catalog-info.yaml")), - [".github/catalog-info.yaml"]) + declaration.targets(self.location(".github/flox-info.yaml")), + [".github/flox-info.yaml"]) def test_an_ordinary_relative_prefix_is_still_removed(self): self.assertEqual( - declaration.targets(self.location("./src/web-ui/catalog-info.yaml")), - ["src/web-ui/catalog-info.yaml"]) + declaration.targets(self.location("./src/web-ui/flox-info.yaml")), + ["src/web-ui/flox-info.yaml"]) def test_repeated_prefixes_are_removed_a_segment_at_a_time(self): self.assertEqual( - declaration.targets(self.location("././.github/x/catalog-info.yaml")), - [".github/x/catalog-info.yaml"]) + declaration.targets(self.location("././.github/x/flox-info.yaml")), + [".github/x/flox-info.yaml"])