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 .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
workflow_dispatch:
inputs:
release_tag:
description: Numeric semantic release tag, for example v0.20.15
description: Numeric semantic release tag, for example v0.20.16
required: true
type: string

Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/security-release-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
env:
DAPPER_IMAGE: pasturestack/catalog-service-dapper:${{ github.sha }}
TRIVY_IMAGE: aquasec/trivy:0.74.0@sha256:62b1e65e8869bc4b4c6aa4fa2b21595256c7c2f6018a9d9ad61caf87187c1969
VERSION_OVERRIDE: v0.20.15
VERSION_OVERRIDE: v0.20.16

steps:
- name: Check out candidate
Expand Down Expand Up @@ -74,7 +74,7 @@ jobs:
}

run_ci
artifact="dist/artifacts/catalog-service-0.20.15.tar.xz"
artifact="dist/artifacts/catalog-service-0.20.16.tar.xz"
test -s "$artifact"
cp "$artifact" /tmp/catalog-service-first.tar.xz

Expand All @@ -88,8 +88,8 @@ jobs:
test "$(find evidence/product -maxdepth 1 -type f | wc -l)" -eq 2
test -x evidence/product/catalog-service
test -x evidence/product/catalog-service-sqlite
test "$(evidence/product/catalog-service --version)" = 'v0.20.15'
test "$(evidence/product/catalog-service-sqlite --version)" = 'v0.20.15'
test "$(evidence/product/catalog-service --version)" = 'v0.20.16'
test "$(evidence/product/catalog-service-sqlite --version)" = 'v0.20.16'
sha256sum "$artifact" > evidence/catalog-service.tar.xz.sha256
docker run --rm --entrypoint sh \
--volume "$PWD:/work:ro" \
Expand Down
11 changes: 11 additions & 0 deletions COMPATIBILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@

The migration preserves `/v1-catalog` routes, generated catalog schemas, database table names, template and version resource fields, legacy Compose metadata, version suffix ordering, and upgrade-link behavior.

The v0.20.16 candidate adds only `GET /v1-catalog/ai/templates`, a private
same-container metadata contract for an authenticated Engine gateway. It uses
the effective project/global visibility of the original Catalog API, with
template/version projection, bounded paging and stable logical identifiers.
It does not replace public Catalog resource IDs or migrate/delete catalog
data. Caller authorization and live Key platform-read evaluation remain in
the Engine; forwarding a client role or IP header cannot authorize this route.
Version bounds are metadata, not a compatibility or launch verdict. Existing
files, questions, readme and launch APIs remain unchanged and outside this
typed interface. Component publication and runtime acceptance remain separate.

Legacy metadata parsing remains compatible without the archived general-purpose Compose parser. Top-level `catalog` and `.catalog` blocks continue to work, Compose v2 continues to read `services[".catalog"]`, and an explicit top-level block keeps precedence when both forms are present. Unrelated service definitions are not interpreted by Catalog Service.

`platformVersion` is the preferred public query parameter. Historical version-query names, `rancher-compose.yml`, `minimumRancherVersion` and `maximumRancherVersion` schema fields, generated `RancherCompose` and `RancherClient` types, legacy repository fixtures, and vendored `github.com/rancher/*` paths remain only as catalog-data, HTTP, or inherited dependency contracts.
Expand Down
7 changes: 7 additions & 0 deletions Dockerfile.dapper
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ ADD --checksum=sha256:5b6326f1932cfd7be57130561dc78192f09ed9f58bfbe6606ed0c50510
ADD --checksum=sha256:2c418a61d7165d0cde01d9cb05ae025cc41fc75ef6d3f095996bd045ba0945dc https://security.ubuntu.com/ubuntu/pool/main/c/curl/curl_8.18.0-1ubuntu2.8_amd64.deb /tmp/curl.deb
ADD --checksum=sha256:8db913e1fa5a694ca6ba7b828bd18c5204e6853ac07fe7ed9c6e1f94e3444d8e https://security.ubuntu.com/ubuntu/pool/main/c/curl/libcurl3t64-gnutls_8.18.0-1ubuntu2.8_amd64.deb /tmp/libcurl3t64-gnutls.deb
ADD --checksum=sha256:7c0b37592f83a629cc22f0c98effa176da9edbd6d77b3f38184a9d0ddc5e0266 https://security.ubuntu.com/ubuntu/pool/main/c/curl/libcurl4t64_8.18.0-1ubuntu2.8_amd64.deb /tmp/libcurl4t64.deb
ADD --checksum=sha256:bedeef1cf3268f90338c411cdb0a45b224d0660fd2240f310f380316c8244606 https://security.ubuntu.com/ubuntu/pool/main/b/brotli/libbrotli1_1.2.0-3ubuntu0.1_amd64.deb /tmp/libbrotli1.deb

ARG DAPPER_HOST_ARCH=amd64
ARG GO_VERSION=1.27.3
Expand Down Expand Up @@ -64,6 +65,12 @@ RUN set -eux; \
for package in curl libcurl3t64-gnutls libcurl4t64; do \
test "$(dpkg-query -W -f='${Version}' "${package}")" = "${UBUNTU_APT_CURL_VERSION}"; \
done; \
test "$(dpkg-query -W -f='${db:Status-Status}' libbrotli1)" = installed; \
test "$(dpkg-deb -f /tmp/libbrotli1.deb Package)" = libbrotli1; \
test "$(dpkg-deb -f /tmp/libbrotli1.deb Version)" = "${UBUNTU_APT_BROTLI_VERSION}"; \
test "$(dpkg-deb -f /tmp/libbrotli1.deb Architecture)" = amd64; \
dpkg -i /tmp/libbrotli1.deb; \
test "$(dpkg-query -W -f='${Version}' libbrotli1)" = "${UBUNTU_APT_BROTLI_VERSION}"; \
dpkg -i /opt/pasturestack-ca-certificates.deb && \
update-ca-certificates --fresh && \
test "$(dpkg-query -W -f='${Version}' ca-certificates)" = '20260816ubuntu0.26.04.1' && \
Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,21 @@ publication and reproducible packaging checks passed; matching Server
integration and acceptance remain separate and are not established by this
component release.

The next numeric candidate, **v0.20.16**, adds a private loopback-only Catalog
metadata interface for typed Engine reads. Template and version IDs derive
from logical catalog identity rather than disposable cache rows. Bounded
responses exclude repository credentials, launch files, questions, defaults
and readme; existing Catalog APIs keep their contracts. See
[the metadata contract](docs/ai-metadata.md). This candidate is not published;
its official Go 1.27.3/security gates and matching Engine/Web runtime
integration are pending.

The candidate builder applies Ubuntu's checksum-pinned
`libbrotli1=1.2.0-3ubuntu0.1` same-series security update for
[USN-8956-1](https://ubuntu.com/security/notices/USN-8956-1). Installed package
identity/version/architecture are checked before the existing raw-to-VEX
equality gate; no Brotli VEX exception is added.

Earlier isolated upgrade checks confirmed removal of empty Git-metadata and
README-only index entries while preserving valid catalog content, plus the
remaining upgrade steps and cleanup of an existing catalog. That evidence
Expand Down
71 changes: 71 additions & 0 deletions docs/ai-metadata.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Bounded Catalog metadata

The new `GET /v1-catalog/ai/templates` route is a private same-container
interface for the Engine's typed Catalog metadata resource. It does not change
the existing Catalog endpoints or their public response contracts.

The handler accepts only a real loopback `RemoteAddr` and one effective
`X-API-Project-Id` header. It does not trust forwarded IP or role headers. The
Engine must authenticate the original Cookie or Basic caller, verify current
project access, and evaluate the original Key's **platform Catalog metadata
read** permission before calling this route. A project-only grant is not a
platform grant. The gateway must use its fixed loopback destination without
redirects, forwarded credentials, arbitrary URLs or new user JWTs. This route
must not be published directly or exposed by a general AI proxy.

Inputs are optional `query` (name substring, at most 256 UTF-16 units), `marker`
(`cmc-<opaque cursor>`), or exclusive logical `templateId` for detail. Unknown or
duplicate selectors are rejected. Project/global visibility and exact catalog
parent ownership are applied in SQL before the fixed 51-row lookahead and
50-row response. Public identities are `ctm-<SHA256 logical identity>` of the
Catalog's global or verified wire-project namespace, Catalog name, canonical
repository URL without userinfo/query/fragment, configured branch/pin, and
template folder/base. They exclude cache row IDs, description, versions and
local filesystem paths. Same-name resources in different scopes/repositories
remain distinct. Credential rotation and cache rebuild do not change identity;
source, branch/pin or template location changes do. No row-ID fallback exists.

The short cursor contains a private cache locator, its logical identity and
query/project binding. It is not a grant or persistent resource ID. The source
revalidates the anchor under the same project/global SQL predicate before the
next page; a changed/reused anchor returns `CatalogMetadataCursorStale`.
Detail recomputes identities from at most 10000 authorized rows and matches the
logical hash, without accepting a caller's DB ID. A larger scan fails closed.

The response is `{resourceType: "catalogTemplate", data: [...], nextMarker}`.
Only template name, description, catalog name, base, scope, configured default
version, maintainer, license and `templateKey` are returned. The key is the
indexer's logical single-component `FolderName`, distinct from display name;
local cache `Path`, absolute paths, URLs, separators and control characters are
rejected. This makes same-name/same-description templates distinguishable
without exposing a local path. Descriptions preserve 1024 UTF-16
units. Truncation is explicit and never splits a Unicode scalar. Catalog URLs,
credentials, compose files, labels, questions/default answers, readme, icons
and version links are excluded. Configured default version is metadata; this
does not verify launch compatibility or implement the Catalog create/launch
form.

Version selection uses the same route with `templateId` and `versions=true`;
an optional marker pages the list and an exclusive `versionId` requests detail.
Name queries are not accepted in this mode. The response resource type is
`catalogTemplateVersion`. Each `cvm-<SHA256>` identity binds the logical template,
version string and nullable revision, never a database row. The parent is
re-authorized on every request, and the version SQL joins and rechecks the
current source identity to reject a source replacement between the two reads.
The cursor is bound to the effective project and logical parent template.

Only version, nullable numeric revision, minimum/maximum platform versions and
upgrade-from metadata are projected. Revision values must fit the consumer's
safe integer range. This is selection metadata, not a compatibility verdict,
launch preview or permission to load files, questions, defaults or readme.

Focused checks:

```sh
go test -count=1 ./internal/aimetadata
go test -count=1 ./service -run '^TestAIMetadataRoute'
```

Engine/Web wiring is developed in separate B3 worktrees. Actual role/Key
integration, release gates with the existing Go 1.27.3 toolchain and
browser/weak-model acceptance remain separate work.
36 changes: 36 additions & 0 deletions docs/releases/catalog-service-0.20.16.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Catalog Service v0.20.16 candidate

Status: unpublished candidate. The official Go 1.27.3 build, full tests/race,
reproducible archives, source/binary/image security and required CodeQL checks
must pass before publication. No release assets, producer or runtime success
are claimed here.

This release adds a fixed, private loopback metadata handler for the Engine's
typed Catalog reader. It returns project-visible and global template metadata
and parent-bound version selection metadata without source credentials, files,
questions, default answers, readme or arbitrary links.

Safe `templateKey` values preserve logical folder identity beside the display
name, so two folders with identical names/descriptions remain selectable. They
cannot contain an absolute/local path, URL or separator. The builder also
applies Ubuntu's exact checksum-pinned libbrotli1 1.2.0-3ubuntu0.1 update for
USN-8956-1, without adding a vulnerability exception or changing the frozen
package baseline.

Logical template IDs bind the catalog scope, name, sanitized repository origin,
branch/pin and template path. Version IDs also bind version and nullable
revision. Cache rebuilds preserve identity; a changed source or reused cache
row cannot rebind a prior ID. Cursor anchors are re-read under the same
authorized parent/project predicates before paging.

Existing read, refresh and launch APIs, database tables, catalog content,
operator origin policy and build gates retain their behavior. The new handler
trusts only the actual loopback peer and an effective project supplied by the
Engine, with no forwarded credentials or user JWT. Engine owner/Key decisions
and Web opaque references are separate integration responsibilities. A
project-only Key grant does not become a platform Catalog grant.

Catalog create/edit/launch, compatibility resolution, browser/role/weak-model
acceptance and Server deployment are outside this metadata component result.
The previous immutable release remains v0.20.15; rollback uses that numeric
component release and the existing operator configuration/data.
Loading
Loading