Skip to content

release: qualify SCM 0.9.2 product runtime #14

release: qualify SCM 0.9.2 product runtime

release: qualify SCM 0.9.2 product runtime #14

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
name: Test (Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: pip
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e ".[dev]"
- name: Run focused regression suite
env:
SCM_DATA_DIR: /tmp/scm-ci-data-${{ matrix.python-version }}
LLM_PROVIDER: ""
SCM_EMBEDDING_BACKEND: hash
SCM_AUTO_SLEEP_DISABLE: "1"
IDLE_LEARNER_ENABLED: "false"
run: |
pytest \
tests/production \
tests/test_scm_sdk.py \
tests/test_product_runtime_api.py \
tests/test_mcp_contract.py \
tests/test_cloud_auth.py::test_byok_decryption_round_trip \
-q --tb=short
- name: Secret scan tracked files
run: |
python - <<'PY'
import pathlib
import re
import subprocess
import sys
token_re = re.compile(r"(sk-proj-[A-Za-z0-9_-]{20,}|sk-[A-Za-z0-9_-]{20,})")
binary_ext = {
".pdf", ".png", ".jpg", ".jpeg", ".gif", ".zip", ".gz", ".tar",
".sqlite", ".db", ".pyc",
}
tracked = subprocess.check_output(["git", "ls-files"], text=True).splitlines()
hits = []
for name in tracked:
path = pathlib.Path(name)
if path.suffix.lower() in binary_ext:
continue
try:
text = path.read_text(encoding="utf-8")
except Exception:
continue
for match in token_re.finditer(text):
token = match.group(1)
lowered = token.lower()
if "fake" in lowered or "your" in lowered:
continue
line = text.count("\n", 0, match.start()) + 1
hits.append(f"{name}:{line}: possible secret token")
if hits:
print("\n".join(hits))
sys.exit(1)
PY
build:
name: Build distribution artifacts
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: pip
- name: Install build tools
run: |
python -m pip install --upgrade pip
pip install build twine
- name: Build wheel + sdist
run: |
rm -rf dist build *.egg-info
python -m build --wheel --sdist
- name: Validate distribution metadata
run: twine check dist/*
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
wheel-smoke:
name: Installed wheel smoke
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: pip
- name: Download dist artifact
uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- name: Install wheel in a clean temp venv
run: |
python -m venv /tmp/scm-wheel
/tmp/scm-wheel/bin/python -m pip install --upgrade pip
/tmp/scm-wheel/bin/pip install dist/scm_memory-*.whl
- name: Verify installed package data and Python SDK
env:
SCM_DATA_DIR: /tmp/scm-wheel-data
LLM_PROVIDER: ""
SCM_EMBEDDING_BACKEND: hash
SCM_AUTO_SLEEP_DISABLE: "1"
run: |
cd /tmp
/tmp/scm-wheel/bin/python - <<'PY'
import importlib.resources as resources
from scm import SCMClient, SCMEngine
assert SCMClient.__name__ == "SCMClient"
assert resources.files("src.core").joinpath("locales/en.json").is_file()
assert resources.files("src.api").joinpath("static/app.html").is_file()
client = SCMClient(user_id="wheel-smoke", base_url="http://localhost:8765/v1")
assert client.user_id == "wheel-smoke"
engine = SCMEngine(session_id="wheel-smoke", sandbox=True, offline=True)
added = engine.add_memory("Alice is allergic to peanuts.")
assert added["ok"] and added["concepts_added"] >= 1
found = engine.search_memory("what should Alice avoid?")
assert found["ok"]
assert engine.sleep("deep")["ok"]
assert engine.wake_summary()["ok"]
PY
- name: Verify CLI and offline quickstart outside repo
env:
SCM_DATA_DIR: /tmp/scm-wheel-data
LLM_PROVIDER: ""
SCM_EMBEDDING_BACKEND: hash
SCM_AUTO_SLEEP_DISABLE: "1"
run: |
cd /tmp
/tmp/scm-wheel/bin/scm --help
/tmp/scm-wheel/bin/scm version
/tmp/scm-wheel/bin/scm config
/tmp/scm-wheel/bin/scm doctor
/tmp/scm-wheel/bin/scm doctor --json
/tmp/scm-wheel/bin/scm chat --help
/tmp/scm-wheel/bin/scm sleep --help
/tmp/scm-wheel/bin/scm wake-summary --help
/tmp/scm-wheel/bin/scm serve --help
/tmp/scm-wheel/bin/scm demo --help
/tmp/scm-wheel/bin/scm demo --dry-run
/tmp/scm-wheel/bin/scm mcp --help
/tmp/scm-wheel/bin/python "$GITHUB_WORKSPACE/examples/01_quickstart.py"
- name: Verify REST five-tool contract
env:
SCM_DATA_DIR: /tmp/scm-wheel-data
LLM_PROVIDER: ""
SCM_EMBEDDING_BACKEND: hash
SCM_AUTO_SLEEP_DISABLE: "1"
IDLE_LEARNER_ENABLED: "false"
run: |
cd /tmp
/tmp/scm-wheel/bin/scm serve --host 127.0.0.1 --port 8765 > /tmp/scm-server.log 2>&1 &
SERVER_PID=$!
trap 'kill $SERVER_PID || true' EXIT
/tmp/scm-wheel/bin/python - <<'PY'
import json
import time
import urllib.request
BASE = "http://127.0.0.1:8765/v1"
def req(method, path, payload=None):
data = None
headers = {}
if payload is not None:
data = json.dumps(payload).encode()
headers["Content-Type"] = "application/json"
request = urllib.request.Request(BASE + path, data=data, headers=headers, method=method)
with urllib.request.urlopen(request, timeout=10) as response:
return json.loads(response.read().decode())
for _ in range(60):
try:
if req("GET", "/health")["ok"]:
break
except Exception:
time.sleep(1)
else:
raise SystemExit("SCM server did not become healthy")
tools = req("GET", "/tools?format=openai")["tools"]
assert [t["function"]["name"] for t in tools] == [
"add_memory", "search_memory", "sleep", "wake_summary", "forget"
]
user = "ci-wheel-smoke"
added = req("POST", "/memories", {
"user_id": user,
"text": "Alice is allergic to peanuts.",
"sync": True,
})
assert added["ok"] and added["concepts_added"] >= 1
assert req("POST", "/memories/search", {
"user_id": user,
"query": "what should Alice avoid?",
"wait_for_pending": True,
})["ok"]
assert req("POST", "/memories/sleep", {"user_id": user, "mode": "deep"})["user_id"] == user
assert req("GET", f"/wake-summary?user_id={user}&since_hours=24")["ok"]
PY
- name: Verify JS SDK unit smoke
run: |
cd sdk/js
npm test
npm pack --dry-run
npm pack --dry-run