Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
da22607
feat(release): add release-readiness evaluator and evidence adapters …
ajdelaguila Jul 13, 2026
d241305
feat: improve kb_record_event tool definition for Glama catalog (gh #…
ajdelaguila Jul 17, 2026
94b1cc2
feat: improve tool definitions for 7 tools (gh #154 / KNA-144)
ajdelaguila Jul 17, 2026
9995e55
fix(deps): bump mcp for security gate
ajdelaguila Jul 17, 2026
6d821db
fix(index): harden Glama empty index reads
ajdelaguila Jul 17, 2026
2ec7ffd
docs(glama): add related server metadata
ajdelaguila Jul 17, 2026
903767f
build: bump mcp from 1.28.0 to 1.28.1
dependabot[bot] Jul 18, 2026
ec8c9f4
build: bump torch from 2.12.1 to 2.13.0
dependabot[bot] Jul 18, 2026
aa3d0fc
Merge remote-tracking branch 'origin/main' into feature/kna-141
ajdelaguila Jul 18, 2026
58918c9
build: bump fastmcp from 3.4.3 to 3.4.4
dependabot[bot] Jul 18, 2026
2512811
build: bump regex from 2026.5.9 to 2026.7.10
dependabot[bot] Jul 18, 2026
4175e3a
build: bump types-regex from 2026.6.28.20260630 to 2026.7.10.20260711
dependabot[bot] Jul 18, 2026
31e1678
build: bump mypy from 2.2.0 to 2.3.0
dependabot[bot] Jul 18, 2026
e527663
build: bump ruff from 0.15.20 to 0.15.22
dependabot[bot] Jul 18, 2026
737b6a6
docs(changelog): record torch security update
ajdelaguila Jul 18, 2026
c4fad07
chore(release): v0.6.0
ajdelaguila Jul 18, 2026
e2c1e0f
docs(changelog): add 0.6.0 compare links
ajdelaguila Jul 18, 2026
e5fba71
fix(release): build images from requested ref
ajdelaguila Jul 18, 2026
cdbe6ab
fix(release): build images from requested ref (#167)
ajdelaguila Jul 18, 2026
ba269eb
Merge remote-tracking branch 'origin/main' into feature/kna-141
ajdelaguila Jul 18, 2026
268fbdb
docs(release): define expanded 0.6.0 design
ajdelaguila Jul 18, 2026
e27f204
Merge remote-tracking branch 'origin/pr-159' into feature/kna-141
ajdelaguila Jul 18, 2026
da67e57
Merge remote-tracking branch 'origin/pr-160' into feature/kna-141
ajdelaguila Jul 18, 2026
d007f0f
Merge remote-tracking branch 'origin/pr-162' into feature/kna-141
ajdelaguila Jul 18, 2026
1c1b727
Merge remote-tracking branch 'origin/pr-163' into feature/kna-141
ajdelaguila Jul 18, 2026
9c0582f
build(deps): require FastMCP search transforms
ajdelaguila Jul 18, 2026
8989ab1
Merge remote-tracking branch 'origin/pr-161' into feature/kna-141
ajdelaguila Jul 18, 2026
9e15580
docs(changelog): record dependency baseline
ajdelaguila Jul 18, 2026
f1155d4
test(deps): verify hidden tool delegation
ajdelaguila Jul 18, 2026
bd69d27
feat(mcp): add searchable tool discovery
ajdelaguila Jul 18, 2026
a7d04cf
test(okf): add executable reference conformance
ajdelaguila Jul 18, 2026
5f3dccd
feat(release): verify candidate artifact provenance
ajdelaguila Jul 18, 2026
5d5d596
docs(changelog): record searchable tool discovery
ajdelaguila Jul 18, 2026
56b2124
feat(release): publish complete candidate channels
ajdelaguila Jul 18, 2026
0a07b67
docs(quickstart): make PyPI the primary install path
ajdelaguila Jul 18, 2026
b242bd8
fix(release): require explicit stable promotion
ajdelaguila Jul 18, 2026
4895499
feat(benchmarks): add provenance receipt support
ajdelaguila Jul 18, 2026
2d288df
fix(benchmarks): validate receipt source commit
ajdelaguila Jul 18, 2026
b4043ad
feat(benchmarks): add reproduction provenance receipt
ajdelaguila Jul 18, 2026
f309332
fix(benchmarks): verify derived receipt claims
ajdelaguila Jul 18, 2026
d425a07
test(benchmarks): refresh verified provenance
ajdelaguila Jul 18, 2026
1eadbcd
docs(release): align complete candidate contract
ajdelaguila Jul 18, 2026
588377e
fix(ci): fetch benchmark receipt source history
ajdelaguila Jul 18, 2026
a7d28cd
fix(release): allow optional skipped checks
ajdelaguila Jul 18, 2026
b2fc85f
fix(release): close candidate verification gaps
ajdelaguila Jul 18, 2026
ee04c6c
fix(release): ignore PyPI attestation sidecars
ajdelaguila Jul 18, 2026
671655a
Merge pull request #165 from knaisoma/feature/kna-141
ajdelaguila Jul 18, 2026
f8aeaef
Add OKF BundleDex badge (#168)
mcclawd Jul 21, 2026
43acd30
build: bump fastmcp from 3.4.4 to 3.4.5
dependabot[bot] Jul 29, 2026
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: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
tests/okf/LICENSE.upstream.md whitespace=-blank-at-eof linguist-vendored
tests/okf/upstream-sample/** linguist-vendored
26 changes: 26 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,35 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
# The benchmark receipt binds artifacts to the execution commit,
# which is intentionally the parent of the receipt commit.
fetch-depth: 0
- uses: astral-sh/setup-uv@v7
- run: uv venv --python 3.13
- run: uv pip install -e '.[dev]'
- name: Read pinned OKF revision
id: okf-pin
run: |
python3 - <<'PY' >> "$GITHUB_OUTPUT"
import json
from pathlib import Path

pin = json.loads(Path("tests/okf/reference.json").read_text())
print(f"sha={pin['commit']}")
PY
- name: Check out the exact official OKF revision
uses: actions/checkout@v7
with:
repository: GoogleCloudPlatform/knowledge-catalog
ref: ${{ steps.okf-pin.outputs.sha }}
path: to-delete/okf-reference
persist-credentials: false
- name: Prove bidirectional OKF interoperability
run: |
uv run python scripts/okf_conformance.py verify-pin
uv run python scripts/okf_conformance.py consume-data-olympus --upstream-root to-delete/okf-reference
uv run python scripts/okf_conformance.py consume-upstream
- run: uv run ruff check .
- run: uv run mypy src
- name: Benchmark docs drift guard (docs match committed results)
Expand Down
140 changes: 140 additions & 0 deletions .github/workflows/okf-pin-freshness.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
name: OKF pin freshness

on:
schedule:
- cron: "17 7 * * 1"
workflow_dispatch:

permissions:
contents: read
issues: write

jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Compare the pin with official OKF main
uses: actions/github-script@v8
with:
script: |
const fs = require("fs");
const crypto = require("crypto");
const pin = JSON.parse(
fs.readFileSync("tests/okf/reference.json", "utf8")
);
const title = "[automation] OKF reference pin is stale";
const upstream = await github.rest.repos.getCommit({
owner: "GoogleCloudPlatform",
repo: "knowledge-catalog",
ref: "main",
});
const upstreamSha = upstream.data.sha;
const tree = await github.rest.git.getTree({
owner: "GoogleCloudPlatform",
repo: "knowledge-catalog",
tree_sha: upstream.data.commit.tree.sha,
recursive: "true",
});
if (tree.data.truncated) {
throw new Error("upstream tree response was truncated");
}
const prefix = `${pin.fixture_path}/`;
const blobs = tree.data.tree
.filter(item => item.type === "blob" && item.path.startsWith(prefix))
.sort((left, right) =>
left.path < right.path ? -1 : left.path > right.path ? 1 : 0
);
if (blobs.length === 0) {
throw new Error(`upstream fixture is missing at ${pin.fixture_path}`);
}
const hash = crypto.createHash("sha256");
for (const blob of blobs) {
const response = await github.rest.git.getBlob({
owner: "GoogleCloudPlatform",
repo: "knowledge-catalog",
file_sha: blob.sha,
});
const content = Buffer.from(response.data.content.replace(/\n/g, ""), "base64");
hash.update(`./${blob.path.slice(prefix.length)}`);
hash.update("\0");
hash.update(content);
hash.update("\0");
}
const upstreamFixtureSha256 = hash.digest("hex");
const listed = await github.paginate(
github.rest.issues.listForRepo,
{
owner: context.repo.owner,
repo: context.repo.repo,
state: "all",
per_page: 100,
}
);
const matches = listed.filter(
issue => !issue.pull_request && issue.title === title
);
const canonical = matches[0];

for (const duplicate of matches.slice(1)) {
if (duplicate.state === "open") {
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: duplicate.number,
state: "closed",
state_reason: "not_planned",
});
}
}

if (pin.fixture_sha256 === upstreamFixtureSha256) {
core.info(`OKF fixture remains current at upstream ${upstreamSha}`);
if (canonical && canonical.state === "open") {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: canonical.number,
body: `The pinned fixture content is current again at upstream \`${upstreamSha}\`. Closing.`,
});
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: canonical.number,
state: "closed",
state_reason: "completed",
});
}
return;
}

const body = [
"The official Google OKF fixture has changed beyond the reviewed pin.",
"",
`* Recorded pin: \`${pin.commit}\``,
`* Current upstream: \`${upstreamSha}\``,
`* Recorded fixture SHA256: \`${pin.fixture_sha256}\``,
`* Current fixture SHA256: \`${upstreamFixtureSha256}\``,
"",
"Review the upstream diff, refresh the vendored fixture and license provenance,",
"rerun both conformance directions, and update the pin in a reviewed pull request.",
"This workflow never changes the pin automatically.",
].join("\n");

if (canonical) {
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: canonical.number,
title,
body,
state: "open",
});
} else {
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title,
body,
});
}
85 changes: 61 additions & 24 deletions .github/workflows/publish-pypi-reusable.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
# .github/workflows/publish-pypi-reusable.yml
#
# INERT UNTIL OPERATOR SETUP. This workflow uploads to PyPI via Trusted
# Publishing (OIDC, no API token). It CANNOT succeed until the operator creates
# a pending publisher on pypi.org. PyPI binds the publisher to the TOP-LEVEL
# workflow that starts the run, and this reusable workflow is called from TWO of
# them, so BOTH need a publisher (same owner=knaisoma, repo=data-olympus,
# environment=pypi):
# - workflow=tag-release.yml (PRIMARY: normal main-merge release path)
# - workflow=publish-pypi.yml (fallback: human-pushed tag / manual dispatch)
# See docs/releases/pypi-trusted-publishing.md for the exact click-path. Until
# then the `upload` job's publish STEP fails (nothing is uploaded); the `build`
# job and `twine check` still pass, so the release tag/image are unaffected.
# This workflow uploads to PyPI via Trusted Publishing (OIDC, no API token).
# PyPI binds the publisher to the TOP-LEVEL
# workflow that starts the run. This reusable workflow is now called only from
# publish-pypi.yml, the human-pushed tag and manual fallback. The primary
# rc-publish.yml and tag-release.yml paths publish inline and have their own
# publisher identities.
# See docs/releases/pypi-trusted-publishing.md for the exact setup path. A
# missing publisher or a registry mismatch fails the caller closed.
name: publish-pypi-reusable

on:
Expand All @@ -31,6 +28,8 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- name: Checkout
uses: actions/checkout@v7
Expand All @@ -39,16 +38,27 @@ jobs:
fetch-depth: 0
- name: Set up uv
uses: astral-sh/setup-uv@v7
- name: Read expected package version
id: version
run: |
python3 - <<'PY' >> "$GITHUB_OUTPUT"
import tomllib

with open("pyproject.toml", "rb") as stream:
print(f"version={tomllib.load(stream)['project']['version']}")
PY
- name: Build sdist + wheel
run: uv build
- name: Verify metadata (twine check)
run: uvx twine check --strict dist/*
- name: Smoke-test the built wheel
# Confirms the console entry point and the packaged bin/ machinery ship
# correctly, so a broken build is caught BEFORE any PyPI upload.
- name: Smoke-test the built distributions
env:
VERSION: ${{ steps.version.outputs.version }}
run: |
uvx --from ./dist/*.whl data-olympus --help
uvx --from ./dist/*.whl data-olympus setup --check --no-version-check
for artifact in dist/*.whl dist/*.tar.gz; do
uv run python scripts/smoke_installed_wheel.py \
--artifact "$artifact" --expected-version "$VERSION"
done
- name: Upload build artifacts
uses: actions/upload-artifact@v7
with:
Expand Down Expand Up @@ -79,15 +89,42 @@ jobs:
path: dist/
- name: Publish to PyPI (Trusted Publishing)
uses: pypa/gh-action-pypi-publish@release/v1
# continue-on-error keeps this INERT until the operator configures the
# pypi.org Trusted Publisher: before that, the OIDC exchange fails, but a
# failed upload here must not fail the release (the tag + image are already
# published by the caller). Once the publisher exists the upload succeeds.
# A step-level continue-on-error is the correct mechanism; a `uses:` job in
# the caller cannot carry continue-on-error.
continue-on-error: true
# No `password:` / token: OIDC Trusted Publishing only. skip-existing so a
# No `password:` or token: OIDC Trusted Publishing only. skip-existing so a
# partial-failure rerun of an already-uploaded version is a no-op, not an
# error (mirrors the idempotent tag/image/release jobs).
with:
skip-existing: true
- name: Verify PyPI files by SHA256
env:
PYPI_VERSION: ${{ needs.build.outputs.version }}
run: |
python3 - <<'PY'
import hashlib
import json
import os
import pathlib
import time
import urllib.request

url = f"https://pypi.org/pypi/data-olympus/{os.environ['PYPI_VERSION']}/json"
for attempt in range(12):
try:
with urllib.request.urlopen(url, timeout=15) as response:
payload = json.load(response)
break
except Exception:
if attempt == 11:
raise
time.sleep(5)
remote = {item["filename"]: item["digests"]["sha256"] for item in payload["urls"]}
dist = pathlib.Path("dist")
artifacts = sorted([*dist.glob("*.whl"), *dist.glob("*.tar.gz")])
if not artifacts:
raise SystemExit("No publishable Python artifacts found")
local = {
path.name: hashlib.sha256(path.read_bytes()).hexdigest()
for path in artifacts
}
if remote != local:
raise SystemExit(f"PyPI SHA256 mismatch: local={local}, remote={remote}")
PY
13 changes: 7 additions & 6 deletions .github/workflows/publish-pypi.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
# .github/workflows/publish-pypi.yml
#
# INERT UNTIL OPERATOR SETUP. The `upload` path (real releases + manual tag)
# cannot succeed until the operator configures a PyPI Trusted Publisher on
# REQUIRES OPERATOR SETUP. The `upload` path for real releases and manual tags
# fails closed until the operator configures a PyPI Trusted Publisher on
# pypi.org: owner=knaisoma, repo=data-olympus, workflow=publish-pypi.yml,
# environment=pypi. See docs/releases/pypi-trusted-publishing.md.
#
# NORMAL RELEASE PATH: this file is NOT the primary release trigger. The live
# release chain is tag-release.yml (on: push main -> should_tag.py -> tag pushed
# with GITHUB_TOKEN). Because GITHUB_TOKEN-created tag pushes do NOT trigger
# release chain uses inline Trusted Publishing jobs in rc-publish.yml and
# tag-release.yml. Because GITHUB_TOKEN-created tag pushes do NOT trigger
# `on: push tags` workflows, the `release` job below does not fire in the normal
# flow; tag-release.yml calls publish-pypi-reusable.yml directly (mirroring how
# it builds the image). This file provides two things tag-release.yml cannot:
# flow. This file provides two independent fallback paths:
# 1. a PR-time DRY RUN (build + twine check, no upload) for packaging changes;
# 2. a manual-tag / human-pushed-tag FALLBACK (same rationale as
# release-image.yml's tag trigger, STD-U-810 section 9).
Expand All @@ -23,6 +22,8 @@ on:
- "pyproject.toml"
- "src/**"
- "bin/**"
- "scripts/smoke_installed_wheel.py"
- "tests/test_installed_wheel_smoke.py"
- ".github/workflows/publish-pypi*.yml"
# FALLBACK for a human-pushed tag (tag-release.yml's GITHUB_TOKEN push does not
# reach here). Real upload.
Expand Down
Loading
Loading