mirror of
https://github.com/semantica-agi/semantica.git
synced 2026-09-01 04:00:28 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
68f78ff234 |
@@ -101,29 +101,6 @@ updates:
|
||||
allow:
|
||||
- dependency-type: "production"
|
||||
|
||||
# Explorer frontend (npm)
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/explorer"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "monday"
|
||||
time: "03:30" # 3:30 AM UTC (9:00 AM IST)
|
||||
open-pull-requests-limit: 10
|
||||
reviewers:
|
||||
- "KaifAhmad1"
|
||||
assignees:
|
||||
- "KaifAhmad1"
|
||||
commit-message:
|
||||
prefix: "security"
|
||||
include: "scope"
|
||||
labels:
|
||||
- "dependencies"
|
||||
- "javascript"
|
||||
- "security"
|
||||
allow:
|
||||
- dependency-type: "production"
|
||||
- dependency-type: "development"
|
||||
|
||||
# Docker dependencies (if you use Docker)
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/"
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
name: Container Security Scan
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
# Mirrors .dockerignore's opt-in list exactly - anything not listed there
|
||||
# can't reach the build context, so it can't change the built image.
|
||||
paths:
|
||||
- 'Dockerfile'
|
||||
- '.dockerignore'
|
||||
- 'pyproject.toml'
|
||||
- 'README.md'
|
||||
- 'LICENSE'
|
||||
- 'MANIFEST.in'
|
||||
- 'semantica/**'
|
||||
- 'integrations/**'
|
||||
- 'explorer/**'
|
||||
- '.github/workflows/container-scan.yml'
|
||||
schedule:
|
||||
- cron: '30 2 * * 1' # weekly, catches new CVEs published against the base image between pushes
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
scan:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
security-events: write # for github/codeql-action/upload-sarif below
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
|
||||
- name: Build image
|
||||
run: docker build -t semantica:scan .
|
||||
|
||||
# Run Trivy as a digest-pinned image rather than the aquasecurity/trivy-action
|
||||
# marketplace wrapper: the aquasecurity GitHub org has an IP allow list on its
|
||||
# API that 403s verify-action-pins.sh's live tag->SHA check from Actions-runner
|
||||
# IPs, and this repo already treats Trivy's action pin as a known past target
|
||||
# for tag-repointing (see the LiteLLM/Trivy 2026 incident note above). Pulling
|
||||
# by sha256 digest from Docker Hub is immutable and verifiable independently of
|
||||
# GitHub's API, so it sidesteps both problems at once instead of carving a skip
|
||||
# exception into the pin verifier for an org already flagged as higher-risk.
|
||||
#
|
||||
# Report-only for now: this is Trivy's first run against this image, so we
|
||||
# don't yet know the CRITICAL/HIGH baseline. Findings still land in the
|
||||
# Security tab either way. Once triaged, add `--exit-code 1` (like
|
||||
# Safety/Bandit-HIGH in security-scan.yml) to make it a hard gate.
|
||||
- name: Scan image for vulnerabilities (Trivy)
|
||||
run: |
|
||||
docker run --rm \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v "$PWD:/output" \
|
||||
aquasec/trivy@sha256:62b1e65e8869bc4b4c6aa4fa2b21595256c7c2f6018a9d9ad61caf87187c1969 \
|
||||
image --format sarif --output /output/trivy-results.sarif \
|
||||
--severity CRITICAL,HIGH --ignore-unfixed semantica:scan
|
||||
|
||||
- name: Upload Trivy SARIF
|
||||
if: always()
|
||||
uses: github/codeql-action/upload-sarif@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4
|
||||
with:
|
||||
sarif_file: trivy-results.sarif
|
||||
category: trivy-container
|
||||
|
||||
- name: Generate SBOM (Syft)
|
||||
if: always()
|
||||
uses: anchore/sbom-action@3ad7283483fc7af8ff2b4ea19663c2d5ca935e26 # v0.24.2
|
||||
with:
|
||||
image: semantica:scan
|
||||
format: spdx-json
|
||||
output-file: semantica-sbom.spdx.json
|
||||
@@ -1,99 +0,0 @@
|
||||
name: Integration Tests
|
||||
|
||||
# Separate from ci.yml, which is a required check: a slow image pull or a
|
||||
# container flake must not block unrelated merges.
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- 'docs_check.py'
|
||||
- '**/*.md'
|
||||
schedule:
|
||||
- cron: '0 5 * * 1'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
pgvector:
|
||||
name: pgvector (live PostgreSQL)
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
|
||||
services:
|
||||
postgres:
|
||||
# pgvector/pgvector:pg16 as published 2026-08-13. Pinned by digest like
|
||||
# the action pins, though verify-action-pins.sh does not check images.
|
||||
image: pgvector/pgvector@sha256:ccc6e83d6e35e931dc7c5def2022729d5a6c370318d099181995567ff1fb4d6b
|
||||
env:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_DB: test
|
||||
# Throwaway container reachable only from this job, so trust auth
|
||||
# avoids putting a credential in the workflow at all.
|
||||
POSTGRES_HOST_AUTH_METHOD: trust
|
||||
ports:
|
||||
- 5432:5432
|
||||
options: >-
|
||||
--health-cmd "pg_isready -U postgres -d test"
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 10
|
||||
|
||||
env:
|
||||
TEST_PGVECTOR_URL: postgresql://postgres@localhost:5432/test
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
|
||||
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7
|
||||
with:
|
||||
python-version: '3.11'
|
||||
cache: 'pip'
|
||||
|
||||
- name: Install semantica with the pgvector extra
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -e ".[vectorstore-pgvector]" pytest==9.1.1
|
||||
|
||||
- name: Create the vector extension
|
||||
# PgVectorStore._verify_pgvector_extension() requires it and refuses to
|
||||
# create it. Doubles as the connectivity gate.
|
||||
run: |
|
||||
python - <<'PY'
|
||||
import os
|
||||
|
||||
import psycopg
|
||||
|
||||
with psycopg.connect(os.environ["TEST_PGVECTOR_URL"]) as conn:
|
||||
conn.execute("CREATE EXTENSION IF NOT EXISTS vector")
|
||||
conn.commit()
|
||||
print("vector extension ready")
|
||||
PY
|
||||
|
||||
- name: Run the live pgvector suite
|
||||
run: |
|
||||
pytest tests/vector_store/test_pgvector_store.py -v -rs \
|
||||
--junit-xml=junit.xml
|
||||
|
||||
- name: Fail if the suite skipped instead of running
|
||||
# The suite skips itself when it cannot reach Postgres, so pytest would
|
||||
# exit 0 having run nothing. Without this the job is green either way.
|
||||
if: always()
|
||||
run: |
|
||||
python - <<'PY'
|
||||
import sys
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
root = ET.parse("junit.xml").getroot()
|
||||
suites = root.findall("testsuite") or [root]
|
||||
total = sum(int(s.get("tests", 0)) for s in suites)
|
||||
skipped = sum(int(s.get("skipped", 0)) for s in suites)
|
||||
|
||||
if total == 0:
|
||||
sys.exit("no tests were collected")
|
||||
if skipped:
|
||||
sys.exit(f"{skipped} of {total} tests skipped; the live suite did not run")
|
||||
print(f"{total} tests ran, none skipped")
|
||||
PY
|
||||
@@ -10,7 +10,7 @@ To run these tests locally with Docker:
|
||||
-e POSTGRES_PASSWORD=postgres \
|
||||
-e POSTGRES_DB=test \
|
||||
-p 5432:5432 \
|
||||
pgvector/pgvector:pg16
|
||||
ankane/pgvector:latest
|
||||
|
||||
pytest tests/vector_store/test_pgvector_store.py -v
|
||||
|
||||
@@ -191,9 +191,7 @@ class TestPgVectorStoreAdd:
|
||||
ids = store.add(vectors, metadata)
|
||||
|
||||
assert len(ids) == 5
|
||||
assert len(set(ids)) == 5
|
||||
# add() assigns uuid4 identifiers, not a "vec_" prefix
|
||||
assert all(uuid.UUID(vector_id) for vector_id in ids)
|
||||
assert all(id.startswith("vec_") for id in ids)
|
||||
|
||||
def test_add_auto_generate_ids(self, store):
|
||||
"""Test that IDs are auto-generated if not provided."""
|
||||
@@ -292,37 +290,19 @@ class TestPgVectorStoreSearch:
|
||||
if not pg_available:
|
||||
pytest.skip("PostgreSQL not available")
|
||||
|
||||
from semantica.vector_store.pgvector_store import PgVectorStore, psycopg_sql
|
||||
from semantica.vector_store.pgvector_store import PgVectorStore
|
||||
|
||||
# setup_vectors is autouse and seeds unique_table_name, and fixtures are
|
||||
# cached per test, so this needs a table of its own to be empty at all.
|
||||
empty_table = f"{unique_table_name}_empty"
|
||||
empty_store = PgVectorStore(
|
||||
connection_string=TEST_CONNECTION_STRING,
|
||||
table_name=empty_table,
|
||||
table_name=unique_table_name,
|
||||
dimension=128,
|
||||
distance_metric="cosine",
|
||||
)
|
||||
|
||||
try:
|
||||
query = np.random.rand(128).astype(np.float32)
|
||||
results = empty_store.search(query, top_k=5)
|
||||
query = np.random.rand(128).astype(np.float32)
|
||||
results = empty_store.search(query, top_k=5)
|
||||
|
||||
assert len(results) == 0
|
||||
finally:
|
||||
try:
|
||||
with empty_store._get_connection() as conn:
|
||||
cur = conn.cursor()
|
||||
cur.execute(
|
||||
psycopg_sql.SQL("DROP TABLE IF EXISTS {}").format(
|
||||
psycopg_sql.Identifier(empty_table)
|
||||
)
|
||||
)
|
||||
conn.commit()
|
||||
cur.close()
|
||||
empty_store.close()
|
||||
except Exception:
|
||||
pass
|
||||
assert len(results) == 0
|
||||
|
||||
# Cleanup: Drop test table after test completes
|
||||
# Uses best-effort cleanup - failures are silently ignored since
|
||||
|
||||
Reference in New Issue
Block a user