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
23 changes: 23 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ jobs:
- name: Generate SPDX SBOM
uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0
with:
syft-version: v1.51.1
path: target/release-package/model-port-${{ github.ref_name }}-linux-amd64
format: spdx-json
output-file: dist/model-port-${{ github.ref_name }}-linux-amd64.spdx.json
Expand Down Expand Up @@ -240,13 +241,35 @@ jobs:

- name: Generate container SPDX SBOM
uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0
env:
SYFT_SELECT_CATALOGERS: +rust-cargo-lock-cataloger,+javascript-lock-cataloger
with:
syft-version: v1.51.1
image: ${{ steps.image.outputs.name }}@${{ steps.push.outputs.digest }}
format: spdx-json
output-file: dist/${{ matrix.image }}-${{ github.ref_name }}-linux-amd64.spdx.json
upload-artifact: false
upload-release-assets: false

- name: Verify SBOM includes locked application dependencies
env:
RELEASE_IMAGE: ${{ matrix.image }}
run: |
python3 - "dist/${RELEASE_IMAGE}-${GITHUB_REF_NAME}-linux-amd64.spdx.json" <<'PYCODE'
import json
import os
import sys
with open(sys.argv[1], encoding="utf-8") as handle:
sbom = json.load(handle)
ecosystem = "npm" if os.environ["RELEASE_IMAGE"] == "modelport-dashboard" else "cargo"
assert any(
ref.get("referenceType") == "purl"
and ref.get("referenceLocator", "").startswith(f"pkg:{ecosystem}/")
for package in sbom.get("packages", [])
for ref in package.get("externalRefs", [])
), f"container SBOM is missing the locked {ecosystem} dependency inventory"
PYCODE

- name: Attest container SBOM
uses: actions/attest@f7c74d28b9d84cb8768d0b8ca14a4bac6ef463e6 # v4.2.0
with:
Expand Down
14 changes: 13 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ All notable ModelPort changes are recorded here. The project follows

## [Unreleased]

## [0.1.3] - 2026-09-07

### Release correction

- Include locked Rust and npm application dependency metadata in runtime
images, outside the dashboard's web root. Container SPDX inventories now
include application dependencies alongside operating-system packages.
- Fail release publication if a container SBOM lacks the expected Cargo/npm
entries. Earlier container SBOMs covered operating-system packages only;
their artifacts and tags remain unchanged.

## [0.1.2] - 2026-09-07

### Authentication and production acceptance
Expand Down Expand Up @@ -143,7 +154,8 @@ Back up PostgreSQL and run a restore drill before upgrading. Compose still uses
the PostgreSQL 18 volume `modelport_modelport-postgres-18`; export any older
volume before removing it.

[Unreleased]: https://github.com/tiammomo/ModelPort/compare/v0.1.2...HEAD
[Unreleased]: https://github.com/tiammomo/ModelPort/compare/v0.1.3...HEAD
[0.1.3]: https://github.com/tiammomo/ModelPort/releases/tag/v0.1.3
[0.1.2]: https://github.com/tiammomo/ModelPort/releases/tag/v0.1.2
[0.1.1]: https://github.com/tiammomo/ModelPort/releases/tag/v0.1.1
[0.1.0]: https://github.com/tiammomo/ModelPort/tree/v0.1.0
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "model-port"
version = "0.1.2"
version = "0.1.3"
edition = "2024"
rust-version = "1.96"
description = "A self-hosted multi-protocol model gateway for Anthropic and OpenAI-compatible workflows."
Expand Down Expand Up @@ -29,7 +29,7 @@ axum = { version = "0.8", features = ["macros"] }
futures-util = "0.3"
httpdate = "1"
jsonschema = { version = "0.48", default-features = false }
modelport-ops-protocol = { version = "0.1.2", path = "crates/ops-protocol" }
modelport-ops-protocol = { version = "0.1.3", path = "crates/ops-protocol" }
openidconnect = { version = "4.0.1", default-features = false, features = ["reqwest", "rustls-tls"] }
rand_core = { version = "0.6", features = ["getrandom"] }
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls", "stream"] }
Expand Down
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# syntax=docker/dockerfile:1

ARG RUST_VERSION=1.96.0
ARG MODELPORT_VERSION=0.1.2
ARG MODELPORT_VERSION=0.1.3
ARG MODELPORT_SOURCE_REVISION=unknown
ARG MODELPORT_SOURCE_STATE=unknown
ARG MODELPORT_BUILD_DATE=unknown
Expand Down Expand Up @@ -34,6 +34,7 @@ RUN mkdir -p /data /config \
&& chown -R modelport:modelport /data /config

COPY --from=builder /app/target/release/model-port /usr/local/bin/model-port
COPY --from=builder /app/Cargo.lock /usr/share/modelport/sbom/Cargo.lock

# Keep source metadata after dependency and binary layers so a new commit label
# does not invalidate the slow apt or Rust build cache.
Expand Down
4 changes: 2 additions & 2 deletions crates/ops-agent/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "modelport-ops-agent"
version = "0.1.2"
version = "0.1.3"
edition = "2024"
rust-version = "1.96"
description = "Deterministic, read-only operations agent for ModelPort."
Expand All @@ -10,7 +10,7 @@ publish = false
[dependencies]
anyhow = "1"
axum = "0.8"
modelport-ops-protocol = { version = "0.1.2", path = "../ops-protocol" }
modelport-ops-protocol = { version = "0.1.3", path = "../ops-protocol" }
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] }
serde_json = "1"
sha2 = "0.10"
Expand Down
3 changes: 2 additions & 1 deletion crates/ops-agent/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# syntax=docker/dockerfile:1

ARG RUST_VERSION=1.96.0
ARG MODELPORT_VERSION=0.1.2
ARG MODELPORT_VERSION=0.1.3
ARG MODELPORT_SOURCE_REVISION=unknown
ARG MODELPORT_SOURCE_STATE=unknown
ARG MODELPORT_BUILD_DATE=unknown
Expand Down Expand Up @@ -31,6 +31,7 @@ RUN useradd --system --home /nonexistent --shell /usr/sbin/nologin modelport-ops
&& chown -R modelport-ops:modelport-ops /var/lib/modelport-ops

COPY --from=builder /app/target/release/modelport-ops-agent /usr/local/bin/modelport-ops-agent
COPY --from=builder /app/Cargo.lock /usr/share/modelport/sbom/Cargo.lock

ARG MODELPORT_SOURCE_REVISION
ARG MODELPORT_SOURCE_STATE
Expand Down
2 changes: 1 addition & 1 deletion crates/ops-protocol/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "modelport-ops-protocol"
version = "0.1.2"
version = "0.1.3"
edition = "2024"
rust-version = "1.96"
license = "MIT"
Expand Down
3 changes: 2 additions & 1 deletion dashboard/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1

ARG MODELPORT_VERSION=0.1.2
ARG MODELPORT_VERSION=0.1.3
ARG MODELPORT_SOURCE_REVISION=unknown
ARG MODELPORT_SOURCE_STATE=unknown
ARG MODELPORT_BUILD_DATE=unknown
Expand Down Expand Up @@ -33,6 +33,7 @@ LABEL org.opencontainers.image.title="ModelPort Dashboard" \
COPY deploy/docker/dashboard.nginx-main.conf /etc/nginx/nginx.conf
COPY deploy/docker/dashboard.nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=builder /app/dist /usr/share/nginx/html
COPY --from=builder /app/package.json /app/package-lock.json /usr/share/modelport/sbom/

USER nginx

Expand Down
4 changes: 2 additions & 2 deletions dashboard/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dashboard/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "dashboard",
"private": true,
"version": "0.1.2",
"version": "0.1.3",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
6 changes: 3 additions & 3 deletions deploy/release/compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ services:
max-file: "${MODELPORT_LOG_MAX_FILES:-5}"

modelport:
image: ${MODELPORT_IMAGE:-ghcr.io/tiammomo/modelport:0.1.2}
image: ${MODELPORT_IMAGE:-ghcr.io/tiammomo/modelport:0.1.3}
pull_policy: ${MODELPORT_PULL_POLICY:-missing}
init: true
read_only: true
Expand Down Expand Up @@ -86,7 +86,7 @@ services:
max-file: "${MODELPORT_LOG_MAX_FILES:-5}"

dashboard:
image: ${MODELPORT_DASHBOARD_IMAGE:-ghcr.io/tiammomo/modelport-dashboard:0.1.2}
image: ${MODELPORT_DASHBOARD_IMAGE:-ghcr.io/tiammomo/modelport-dashboard:0.1.3}
pull_policy: ${MODELPORT_PULL_POLICY:-missing}
init: true
read_only: true
Expand All @@ -108,7 +108,7 @@ services:

ops-agent:
profiles: ["ops-agent"]
image: ${MODELPORT_OPS_AGENT_IMAGE:-ghcr.io/tiammomo/modelport-ops-agent:0.1.2}
image: ${MODELPORT_OPS_AGENT_IMAGE:-ghcr.io/tiammomo/modelport-ops-agent:0.1.3}
pull_policy: ${MODELPORT_PULL_POLICY:-missing}
init: true
read_only: true
Expand Down
6 changes: 3 additions & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ services:
context: .
dockerfile: Dockerfile
args:
MODELPORT_VERSION: ${MODELPORT_VERSION:-0.1.2}
MODELPORT_VERSION: ${MODELPORT_VERSION:-0.1.3}
MODELPORT_SOURCE_REVISION: ${MODELPORT_SOURCE_REVISION:-unknown}
MODELPORT_SOURCE_STATE: ${MODELPORT_SOURCE_STATE:-unknown}
MODELPORT_BUILD_DATE: ${MODELPORT_BUILD_DATE:-unknown}
Expand Down Expand Up @@ -99,7 +99,7 @@ services:
context: .
dockerfile: dashboard/Dockerfile
args:
MODELPORT_VERSION: ${MODELPORT_VERSION:-0.1.2}
MODELPORT_VERSION: ${MODELPORT_VERSION:-0.1.3}
MODELPORT_SOURCE_REVISION: ${MODELPORT_SOURCE_REVISION:-unknown}
MODELPORT_SOURCE_STATE: ${MODELPORT_SOURCE_STATE:-unknown}
MODELPORT_BUILD_DATE: ${MODELPORT_BUILD_DATE:-unknown}
Expand Down Expand Up @@ -129,7 +129,7 @@ services:
context: .
dockerfile: crates/ops-agent/Dockerfile
args:
MODELPORT_VERSION: ${MODELPORT_VERSION:-0.1.2}
MODELPORT_VERSION: ${MODELPORT_VERSION:-0.1.3}
MODELPORT_SOURCE_REVISION: ${MODELPORT_SOURCE_REVISION:-unknown}
MODELPORT_SOURCE_STATE: ${MODELPORT_SOURCE_STATE:-unknown}
MODELPORT_BUILD_DATE: ${MODELPORT_BUILD_DATE:-unknown}
Expand Down
12 changes: 11 additions & 1 deletion docs/RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,22 @@ The release workflow:
- builds the Linux amd64 backend archive;
- emits SHA-256 checksums and an SPDX JSON SBOM;
- creates GitHub build-provenance and SBOM attestations;
- publishes versioned backend and dashboard images to GHCR;
- publishes versioned gateway, dashboard and Operations Agent images to GHCR;
- publishes Linux x86_64 container SBOMs, signs immutable image digests with
keyless Cosign, and attaches GitHub provenance/SBOM attestations;
- records all three immutable image references as Release assets;
- creates the GitHub Release from the existing tag.

Runtime images retain their locked application dependency metadata under
`/usr/share/modelport/sbom/`, outside the dashboard's served directory. Container
SBOM verification requires Cargo or npm package entries as well as the scanner's
system package inventory. The pinned Syft scanner explicitly adds its Cargo/npm
[lockfile catalogers](https://oss.anchore.com/docs/guides/sbom/catalogers/), which
are not enabled by the default image scan. Lockfile entries describe build inputs, including
workspace/build dependencies; they do not prove each package is reachable in
the running service. The v0.1.2 and earlier container SBOMs lack this application
inventory; use v0.1.3 or newer for the corrected container evidence.

The tag must resolve to a commit on protected `main`. Publication first creates
a draft and uploads all assets, checks the asset count, then publishes it under
the repository's immutable-release policy. Do not delete or retag a failed
Expand Down
Loading