diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 918a472..5b7b7b2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -111,6 +111,18 @@ jobs: - name: Verify AGENTS.md ↔ docs/ cross-links run: bash scripts/check-agents-md.sh + entrypoint_test: + name: Container Entrypoint + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout source + uses: actions/checkout@v5.0.1 + + - name: Verify omnigraph-server entrypoint arg composition + run: sh docker/entrypoint_test.sh + test: name: Test Workspace needs: classify_changes diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 83b7d34..a5fb275 100644 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -9,8 +9,14 @@ fi bind="${OMNIGRAPH_BIND:-0.0.0.0:8080}" +# URI comes from the env var (the positional arg wins over any config +# `graphs` block in resolve_target_uri). OMNIGRAPH_CONFIG, when also set, +# is forwarded as --config purely to supply a policy file — the two +# compose. Without OMNIGRAPH_CONFIG the behavior is unchanged. if [ -n "${OMNIGRAPH_TARGET_URI:-}" ]; then - exec "$SERVER_BIN" "${OMNIGRAPH_TARGET_URI}" --bind "${bind}" + exec "$SERVER_BIN" "${OMNIGRAPH_TARGET_URI}" \ + ${OMNIGRAPH_CONFIG:+--config "$OMNIGRAPH_CONFIG"} \ + --bind "${bind}" fi if [ -n "${OMNIGRAPH_CONFIG:-}" ]; then @@ -28,5 +34,7 @@ omnigraph-server container startup requires one of: Optional: - OMNIGRAPH_BIND (default: 0.0.0.0:8080) - OMNIGRAPH_TARGET (used with OMNIGRAPH_CONFIG) + - OMNIGRAPH_CONFIG (may also accompany OMNIGRAPH_TARGET_URI to add a + policy file; the URI still comes from OMNIGRAPH_TARGET_URI) EOF exit 64 diff --git a/docker/entrypoint_test.sh b/docker/entrypoint_test.sh new file mode 100755 index 0000000..01fbee2 --- /dev/null +++ b/docker/entrypoint_test.sh @@ -0,0 +1,65 @@ +#!/bin/sh +# Self-contained test for docker/entrypoint.sh argument composition. +# Runs the entrypoint against a stub server that echoes its args, and +# asserts the forwarded argv for each startup mode. No Docker required. +# +# sh docker/entrypoint_test.sh +# +# Exits 0 on success, 1 on the first mismatch. +set -eu + +here=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +entrypoint="$here/entrypoint.sh" + +work=$(mktemp -d) +trap 'rm -rf "$work"' EXIT +mkdir -p "$work/bin" +cat > "$work/bin/omnigraph-server" <<'EOF' +#!/bin/sh +echo "ARGS: $*" +EOF +chmod +x "$work/bin/omnigraph-server" + +# Run the real entrypoint with SERVER_BIN pointed at the stub. +ep="$work/entrypoint.sh" +sed "s#SERVER_BIN=\"/usr/local/bin/omnigraph-server\"#SERVER_BIN=\"$work/bin/omnigraph-server\"#" \ + "$entrypoint" > "$ep" + +fail=0 +check() { + desc=$1; want=$2; got=$3 + if [ "$got" != "$want" ]; then + echo "FAIL: $desc" + echo " want: $want" + echo " got: $got" + fail=1 + else + echo "ok: $desc" + fi +} + +got=$(OMNIGRAPH_TARGET_URI="s3://b/g" OMNIGRAPH_BIND="0.0.0.0:8080" sh "$ep") +check "TARGET_URI only (legacy)" \ + "ARGS: s3://b/g --bind 0.0.0.0:8080" "$got" + +got=$(OMNIGRAPH_TARGET_URI="s3://b/g" OMNIGRAPH_CONFIG="/etc/omnigraph/omnigraph.yaml" OMNIGRAPH_BIND="0.0.0.0:8080" sh "$ep") +check "TARGET_URI + CONFIG composes (policy)" \ + "ARGS: s3://b/g --config /etc/omnigraph/omnigraph.yaml --bind 0.0.0.0:8080" "$got" + +got=$(OMNIGRAPH_CONFIG="/etc/omnigraph/omnigraph.yaml" OMNIGRAPH_BIND="0.0.0.0:8080" sh "$ep") +check "CONFIG only" \ + "ARGS: --config /etc/omnigraph/omnigraph.yaml --bind 0.0.0.0:8080" "$got" + +got=$(OMNIGRAPH_CONFIG="/etc/omnigraph/omnigraph.yaml" OMNIGRAPH_TARGET="active" OMNIGRAPH_BIND="0.0.0.0:8080" sh "$ep") +check "CONFIG + TARGET" \ + "ARGS: --config /etc/omnigraph/omnigraph.yaml --target active --bind 0.0.0.0:8080" "$got" + +got=$(sh "$ep" some-uri --bind 1.2.3.4:9 --extra) +check "explicit args passthrough" \ + "ARGS: some-uri --bind 1.2.3.4:9 --extra" "$got" + +if [ "$fail" -ne 0 ]; then + echo "entrypoint_test: FAILED" + exit 1 +fi +echo "entrypoint_test: all cases passed" diff --git a/docs/user/deployment.md b/docs/user/deployment.md index 8613dec..9a4466c 100644 --- a/docs/user/deployment.md +++ b/docs/user/deployment.md @@ -109,6 +109,35 @@ docker run --rm -p 8080:8080 \ --bind 0.0.0.0:8080 ``` +### Container entrypoint env vars + +When no positional args are given, the image entrypoint +(`docker/entrypoint.sh`) builds the server command from env vars: + +| Var | Effect | +|---|---| +| `OMNIGRAPH_TARGET_URI` | Graph URI, passed as the positional argument. | +| `OMNIGRAPH_CONFIG` | Path to an `omnigraph.yaml`, passed as `--config`. Used to supply a `policy.file` (Cedar authorization). The config file and any relative `policy.file` must be mounted into the container. | +| `OMNIGRAPH_TARGET` | Graph name to select from the config's `graphs:` block (with `OMNIGRAPH_CONFIG`, when no `OMNIGRAPH_TARGET_URI`). | +| `OMNIGRAPH_BIND` | Listen address (default `0.0.0.0:8080`). | + +`OMNIGRAPH_TARGET_URI` and `OMNIGRAPH_CONFIG` **compose**: set both to keep the +graph URI in the env var while loading policy from the config file (the +positional URI wins over any `graphs:` entry). To enable Cedar policy on a +container otherwise driven by `OMNIGRAPH_TARGET_URI`, mount the config dir and +add `OMNIGRAPH_CONFIG`: + +```bash +docker run --rm -p 8080:8080 \ + -e OMNIGRAPH_SERVER_BEARER_TOKEN="change-me" \ + -e OMNIGRAPH_TARGET_URI="s3://my-bucket/graphs/example/releases/2026-04-10-v0.1.0" \ + -e OMNIGRAPH_CONFIG="/etc/omnigraph/omnigraph.yaml" \ + -v "$PWD/config:/etc/omnigraph:ro" \ + omnigraph-server:local +# /etc/omnigraph/omnigraph.yaml contains `policy: { file: ./policy.yaml }`; +# policy.yaml (+ optional policy.tests.yaml) sit beside it in the mount. +``` + ## Auth The server can run unauthenticated for local development only when explicitly