enclave-ontos 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. enclave_ontos-0.1.0/.env.example +118 -0
  2. enclave_ontos-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +88 -0
  3. enclave_ontos-0.1.0/.github/ISSUE_TEMPLATE/config.yml +11 -0
  4. enclave_ontos-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +74 -0
  5. enclave_ontos-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +60 -0
  6. enclave_ontos-0.1.0/.github/workflows/ci.yml +67 -0
  7. enclave_ontos-0.1.0/.github/workflows/release.yml +173 -0
  8. enclave_ontos-0.1.0/.gitignore +24 -0
  9. enclave_ontos-0.1.0/.python-version +1 -0
  10. enclave_ontos-0.1.0/CHANGELOG.md +79 -0
  11. enclave_ontos-0.1.0/CLAUDE.md +53 -0
  12. enclave_ontos-0.1.0/CODE_OF_CONDUCT.md +13 -0
  13. enclave_ontos-0.1.0/CONTRIBUTING.md +113 -0
  14. enclave_ontos-0.1.0/PKG-INFO +133 -0
  15. enclave_ontos-0.1.0/README.md +89 -0
  16. enclave_ontos-0.1.0/RELEASING.md +99 -0
  17. enclave_ontos-0.1.0/SECURITY.md +55 -0
  18. enclave_ontos-0.1.0/deploy/Dockerfile +28 -0
  19. enclave_ontos-0.1.0/deploy/docker-compose.yml +15 -0
  20. enclave_ontos-0.1.0/deploy/helm/README.md +50 -0
  21. enclave_ontos-0.1.0/deploy/helm/ontos/Chart.yaml +22 -0
  22. enclave_ontos-0.1.0/deploy/helm/ontos/templates/_helpers.tpl +33 -0
  23. enclave_ontos-0.1.0/deploy/helm/ontos/templates/configmap.yaml +20 -0
  24. enclave_ontos-0.1.0/deploy/helm/ontos/templates/deployment.yaml +108 -0
  25. enclave_ontos-0.1.0/deploy/helm/ontos/templates/networkpolicy.yaml +45 -0
  26. enclave_ontos-0.1.0/deploy/helm/ontos/templates/service.yaml +15 -0
  27. enclave_ontos-0.1.0/deploy/helm/ontos/templates/serviceaccount.yaml +12 -0
  28. enclave_ontos-0.1.0/deploy/helm/ontos/values.yaml +124 -0
  29. enclave_ontos-0.1.0/docs/architecture.md +61 -0
  30. enclave_ontos-0.1.0/docs/compliance/eu-ai-act-article-12.md +35 -0
  31. enclave_ontos-0.1.0/docs/design/m1.md +237 -0
  32. enclave_ontos-0.1.0/docs/design/m2.md +161 -0
  33. enclave_ontos-0.1.0/docs/design/m3.md +133 -0
  34. enclave_ontos-0.1.0/docs/design/m4.md +188 -0
  35. enclave_ontos-0.1.0/docs/design/m5.md +136 -0
  36. enclave_ontos-0.1.0/docs/design/m6.md +110 -0
  37. enclave_ontos-0.1.0/docs/ontology/examples/starter.yaml +64 -0
  38. enclave_ontos-0.1.0/ontos/__init__.py +5 -0
  39. enclave_ontos-0.1.0/ontos/_version.py +16 -0
  40. enclave_ontos-0.1.0/ontos/audit/__init__.py +22 -0
  41. enclave_ontos-0.1.0/ontos/audit/base.py +38 -0
  42. enclave_ontos-0.1.0/ontos/audit/emitter.py +115 -0
  43. enclave_ontos-0.1.0/ontos/audit/postgres.py +298 -0
  44. enclave_ontos-0.1.0/ontos/authz/__init__.py +16 -0
  45. enclave_ontos-0.1.0/ontos/authz/base.py +53 -0
  46. enclave_ontos-0.1.0/ontos/authz/inmemory.py +37 -0
  47. enclave_ontos-0.1.0/ontos/authz/openfga.py +106 -0
  48. enclave_ontos-0.1.0/ontos/cli/__init__.py +5 -0
  49. enclave_ontos-0.1.0/ontos/cli/main.py +244 -0
  50. enclave_ontos-0.1.0/ontos/executor/__init__.py +16 -0
  51. enclave_ontos-0.1.0/ontos/executor/base.py +65 -0
  52. enclave_ontos-0.1.0/ontos/executor/deterministic.py +240 -0
  53. enclave_ontos-0.1.0/ontos/extraction/__init__.py +28 -0
  54. enclave_ontos-0.1.0/ontos/extraction/base.py +107 -0
  55. enclave_ontos-0.1.0/ontos/extraction/llm_extractor.py +208 -0
  56. enclave_ontos-0.1.0/ontos/ingest/__init__.py +16 -0
  57. enclave_ontos-0.1.0/ontos/ingest/base.py +53 -0
  58. enclave_ontos-0.1.0/ontos/ingest/slack.py +49 -0
  59. enclave_ontos-0.1.0/ontos/ingest/text.py +41 -0
  60. enclave_ontos-0.1.0/ontos/llm/__init__.py +18 -0
  61. enclave_ontos-0.1.0/ontos/llm/ollama.py +196 -0
  62. enclave_ontos-0.1.0/ontos/llm/openai.py +145 -0
  63. enclave_ontos-0.1.0/ontos/llm/prompts.py +69 -0
  64. enclave_ontos-0.1.0/ontos/ontology/__init__.py +25 -0
  65. enclave_ontos-0.1.0/ontos/ontology/loader.py +198 -0
  66. enclave_ontos-0.1.0/ontos/pipeline/__init__.py +19 -0
  67. enclave_ontos-0.1.0/ontos/pipeline/ingest.py +128 -0
  68. enclave_ontos-0.1.0/ontos/planner/__init__.py +33 -0
  69. enclave_ontos-0.1.0/ontos/planner/base.py +49 -0
  70. enclave_ontos-0.1.0/ontos/planner/llm_planner.py +98 -0
  71. enclave_ontos-0.1.0/ontos/planner/plan.py +102 -0
  72. enclave_ontos-0.1.0/ontos/resolver/__init__.py +24 -0
  73. enclave_ontos-0.1.0/ontos/resolver/base.py +77 -0
  74. enclave_ontos-0.1.0/ontos/resolver/cascade.py +57 -0
  75. enclave_ontos-0.1.0/ontos/resolver/rules.py +78 -0
  76. enclave_ontos-0.1.0/ontos/runtime/__init__.py +1 -0
  77. enclave_ontos-0.1.0/ontos/runtime/config.py +38 -0
  78. enclave_ontos-0.1.0/ontos/runtime/models.py +117 -0
  79. enclave_ontos-0.1.0/ontos/runtime/server.py +464 -0
  80. enclave_ontos-0.1.0/ontos/storage/__init__.py +1 -0
  81. enclave_ontos-0.1.0/ontos/storage/base.py +78 -0
  82. enclave_ontos-0.1.0/ontos/storage/neo4j_store.py +312 -0
  83. enclave_ontos-0.1.0/ontos/storage/networkx_store.py +170 -0
  84. enclave_ontos-0.1.0/pyproject.toml +79 -0
  85. enclave_ontos-0.1.0/tests/__init__.py +0 -0
  86. enclave_ontos-0.1.0/tests/benchmarks/__init__.py +0 -0
  87. enclave_ontos-0.1.0/tests/benchmarks/harness.py +108 -0
  88. enclave_ontos-0.1.0/tests/benchmarks/test_synthetic.py +135 -0
  89. enclave_ontos-0.1.0/tests/compliance/__init__.py +0 -0
  90. enclave_ontos-0.1.0/tests/compliance/test_article_twelve.py +114 -0
  91. enclave_ontos-0.1.0/tests/conftest.py +43 -0
  92. enclave_ontos-0.1.0/tests/integration/__init__.py +0 -0
  93. enclave_ontos-0.1.0/tests/integration/test_m1_end_to_end.py +409 -0
  94. enclave_ontos-0.1.0/tests/integration/test_m2_end_to_end.py +379 -0
  95. enclave_ontos-0.1.0/tests/integration/test_m3_end_to_end.py +301 -0
  96. enclave_ontos-0.1.0/tests/integration/test_neo4j_store.py +222 -0
  97. enclave_ontos-0.1.0/tests/integration/test_postgres_audit.py +215 -0
  98. enclave_ontos-0.1.0/tests/unit/__init__.py +0 -0
  99. enclave_ontos-0.1.0/tests/unit/test_authz.py +177 -0
  100. enclave_ontos-0.1.0/tests/unit/test_cli.py +100 -0
  101. enclave_ontos-0.1.0/tests/unit/test_executor.py +248 -0
  102. enclave_ontos-0.1.0/tests/unit/test_extraction_base.py +211 -0
  103. enclave_ontos-0.1.0/tests/unit/test_ingest.py +85 -0
  104. enclave_ontos-0.1.0/tests/unit/test_llm_adapters.py +240 -0
  105. enclave_ontos-0.1.0/tests/unit/test_llm_extractor.py +258 -0
  106. enclave_ontos-0.1.0/tests/unit/test_ontology_loader.py +201 -0
  107. enclave_ontos-0.1.0/tests/unit/test_pipeline.py +265 -0
  108. enclave_ontos-0.1.0/tests/unit/test_planner.py +163 -0
  109. enclave_ontos-0.1.0/tests/unit/test_resolver.py +208 -0
  110. enclave_ontos-0.1.0/tests/unit/test_smoke.py +36 -0
  111. enclave_ontos-0.1.0/tests/unit/test_storage.py +110 -0
  112. enclave_ontos-0.1.0/uv.lock +4488 -0
@@ -0,0 +1,118 @@
1
+ # Ontos environment configuration
2
+ #
3
+ # Copy to `.env` (git-ignored) and fill in the values you actually need.
4
+ # Values are grouped by milestone so you only set what your target
5
+ # milestone requires. M0 needs almost nothing.
6
+ #
7
+ # Sovereignty rule: any variable marked [BRIDGE] sends data outside the
8
+ # customer VPC and is a temporary dev convenience. Production deploys
9
+ # resolve every [BRIDGE] to a customer-controlled endpoint (Ollama /
10
+ # Bedrock / Azure OpenAI / Vertex) or to Enclave Scribe once Scribe
11
+ # passes benchmarks.
12
+
13
+
14
+ # ────────────────────────────────────────────────────────────────
15
+ # M0 — running today
16
+ # ────────────────────────────────────────────────────────────────
17
+
18
+ # Required in prod. In dev (ONTOS_ENV != "prod") the runtime auto-defaults
19
+ # to a loud placeholder — do NOT ship that placeholder to a customer.
20
+ # In prod, derive this from KMS (or the customer's key vault) at boot.
21
+ ONTOS_AUDIT_SIGNING_KEY=dev-only-signing-key-do-not-use
22
+
23
+ # Set to "prod" to make the runtime refuse to boot without a real
24
+ # signing key. Anything else (or unset) is dev mode.
25
+ ONTOS_ENV=dev
26
+
27
+ # Where the MCP server binds. 127.0.0.1 for local dev; 0.0.0.0 in a
28
+ # container behind a reverse proxy.
29
+ ONTOS_LISTEN_HOST=127.0.0.1
30
+ ONTOS_LISTEN_PORT=8765
31
+
32
+ # Which storage backend to use. M0 only supports "networkx" (in-memory).
33
+ # M1 adds "neo4j"; M2 adds "kuzu" (LadybugDB) and "neptune".
34
+ ONTOS_STORAGE_BACKEND=networkx
35
+
36
+ # Where the audit chain persists. SQLite default is fine for dev.
37
+ # M2 swaps to Postgres for regulated deploys (6+ month retention).
38
+ ONTOS_AUDIT_DB_URL=sqlite+pysqlite:///./audit-logs/audit.sqlite
39
+
40
+ # Name of the env var the runtime reads for the signing key.
41
+ # You almost never need to change this — it exists so a deploy can
42
+ # rename the concrete env var (e.g. to match a k8s secret's key).
43
+ ONTOS_AUDIT_SIGNING_KEY_ENV=ONTOS_AUDIT_SIGNING_KEY
44
+
45
+ # Optional: path to a YAML/LinkML ontology file. If unset, the runtime
46
+ # runs schemaless (M0 default).
47
+ # ONTOS_ONTOLOGY_PATH=./docs/ontology/examples/fintech.yaml
48
+
49
+
50
+ # ────────────────────────────────────────────────────────────────
51
+ # M1 — Neo4j storage + first extraction wrappers
52
+ # ────────────────────────────────────────────────────────────────
53
+
54
+ # Neo4j — self-hosted, Aura, or in-VPC cluster the customer runs.
55
+ # NEO4J_URI=bolt://localhost:7687
56
+ # NEO4J_USER=neo4j
57
+ # NEO4J_PASSWORD=
58
+
59
+ # LLM for extraction — pick exactly ONE of the three blocks below.
60
+
61
+ # Option A [BRIDGE]: OpenAI. Fastest to test; violates in-VPC promise.
62
+ # OPENAI_API_KEY=sk-...
63
+ # OPENAI_MODEL=gpt-4o-mini
64
+
65
+ # Option B [BRIDGE]: Anthropic. Better structured extraction than OpenAI.
66
+ # ANTHROPIC_API_KEY=sk-ant-...
67
+ # ANTHROPIC_MODEL=claude-sonnet-5
68
+
69
+ # Option C: Ollama (fully local, no key). This is the sovereignty-preserving
70
+ # path and the shape Scribe eventually replaces.
71
+ # OLLAMA_HOST=http://localhost:11434
72
+ # OLLAMA_MODEL=llama3.1:8b
73
+
74
+ # Embedding model. BGE-m3 runs locally via sentence-transformers.
75
+ # EMBEDDING_MODEL=BAAI/bge-m3
76
+
77
+ # When Enclave Scribe is ready and beats frontier benchmarks, these
78
+ # replace every extraction key above:
79
+ # SCRIBE_ENDPOINT=http://scribe.ontos.svc.cluster.local:9000
80
+ # SCRIBE_MODEL=scribe-v1
81
+
82
+
83
+ # ────────────────────────────────────────────────────────────────
84
+ # M2 — permission-aware traversal + persistent audit
85
+ # ────────────────────────────────────────────────────────────────
86
+
87
+ # OpenFGA (default authz backend). Self-host in-VPC, or point at
88
+ # openfga.dev's hosted plane for dev.
89
+ # FGA_API_URL=http://localhost:8080
90
+ # FGA_STORE_ID=
91
+ # FGA_API_TOKEN=
92
+
93
+ # Alternative: SpiceDB (Authzed). Pick one, not both.
94
+ # SPICEDB_ENDPOINT=localhost:50051
95
+ # SPICEDB_TOKEN=
96
+
97
+ # Postgres for the persistent hash-chained audit log (replaces the M0
98
+ # SQLite default). Regulated deploys must retain ≥6 months.
99
+ # ONTOS_AUDIT_DB_URL=postgresql+psycopg://ontos:changeme@postgres:5432/ontos_audit
100
+
101
+
102
+ # ────────────────────────────────────────────────────────────────
103
+ # M4 — real source connectors (per customer, per tenant, not global)
104
+ # ────────────────────────────────────────────────────────────────
105
+ #
106
+ # These are examples of what a connector config will look like — the
107
+ # real system will load per-tenant credentials from a secure store,
108
+ # not from process env. Do not put customer credentials here.
109
+ #
110
+ # SLACK_BOT_TOKEN=xoxb-...
111
+ # GOOGLE_DRIVE_CLIENT_ID=
112
+ # GOOGLE_DRIVE_CLIENT_SECRET=
113
+ # CONFLUENCE_API_TOKEN=
114
+ # JIRA_API_TOKEN=
115
+ # SALESFORCE_CLIENT_ID=
116
+ # SALESFORCE_CLIENT_SECRET=
117
+ # GITHUB_APP_ID=
118
+ # GITHUB_PRIVATE_KEY=
@@ -0,0 +1,88 @@
1
+ name: Bug report
2
+ description: Something in Ontos doesn't work as documented.
3
+ title: "[bug] "
4
+ labels: ["bug", "triage"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Thanks for the report. Please fill in what you can — every field
10
+ makes triage faster.
11
+
12
+ **Do NOT file a security vulnerability here.** See
13
+ [SECURITY.md](../blob/main/SECURITY.md) for the private
14
+ disclosure path.
15
+
16
+ - type: textarea
17
+ id: what-happened
18
+ attributes:
19
+ label: What happened
20
+ description: What you saw, and what you expected instead.
21
+ validations:
22
+ required: true
23
+
24
+ - type: textarea
25
+ id: reproduction
26
+ attributes:
27
+ label: Minimal reproduction
28
+ description: |
29
+ The smallest snippet, commands, or steps that reliably reproduce
30
+ the issue. If you can't produce a MRE, describe the shape of what
31
+ you were doing instead.
32
+ render: bash
33
+ validations:
34
+ required: true
35
+
36
+ - type: input
37
+ id: version
38
+ attributes:
39
+ label: Ontos version / commit
40
+ description: Output of `uv pip show ontos` or the commit SHA you're on.
41
+ validations:
42
+ required: true
43
+
44
+ - type: input
45
+ id: python
46
+ attributes:
47
+ label: Python version
48
+ description: Output of `python --version`.
49
+ validations:
50
+ required: true
51
+
52
+ - type: dropdown
53
+ id: storage-backend
54
+ attributes:
55
+ label: Storage backend
56
+ options:
57
+ - networkx (M0 in-memory)
58
+ - neo4j
59
+ - kuzu / ladybugdb
60
+ - neptune
61
+ - other / n/a
62
+ validations:
63
+ required: true
64
+
65
+ - type: textarea
66
+ id: logs
67
+ attributes:
68
+ label: Relevant logs / stack trace
69
+ description: |
70
+ Paste any relevant structured log output or a stack trace. Redact
71
+ anything that looks like a customer identifier, credential, or
72
+ piece of regulated data before pasting.
73
+ render: text
74
+ validations:
75
+ required: false
76
+
77
+ - type: checkboxes
78
+ id: touches-compliance
79
+ attributes:
80
+ label: Does this touch a compliance property?
81
+ description: Tick every one that applies. This routes the bug to the right reviewer.
82
+ options:
83
+ - label: Audit chain (Article 12)
84
+ - label: Permission-aware traversal / node-existence leaks
85
+ - label: Bitemporal correctness (`as_of` returns wrong facts)
86
+ - label: Provenance metadata (missing / forged / dropped)
87
+ - label: Sovereignty (unexpected outbound network call)
88
+ - label: None of the above
@@ -0,0 +1,11 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Security vulnerability
4
+ url: https://github.com/getenclave/ontos/blob/main/SECURITY.md
5
+ about: Do NOT open a public issue. Follow the private disclosure path in SECURITY.md.
6
+ - name: Question / help / design discussion
7
+ url: https://github.com/getenclave/ontos/discussions
8
+ about: Use GitHub Discussions for questions and open-ended design conversation.
9
+ - name: Enclave (the parent product)
10
+ url: https://getenclave.ai
11
+ about: Ontos is a subset of Enclave. For anything about the wider Enclave platform, start here.
@@ -0,0 +1,74 @@
1
+ name: Feature / proposal
2
+ description: Suggest a new capability, connector, backend, or design change.
3
+ title: "[proposal] "
4
+ labels: ["proposal", "triage"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Thanks for the idea. Before you start writing code for anything
10
+ architectural (new module, new storage backend, new authz backend,
11
+ new extractor family), please open this issue first so we can
12
+ align on the design.
13
+
14
+ Small fixes, docs, tests, and connector adapters don't need a
15
+ proposal issue — just open a PR.
16
+
17
+ - type: textarea
18
+ id: problem
19
+ attributes:
20
+ label: What problem does this solve
21
+ description: |
22
+ Describe the user or operational pain first. Do NOT lead with a
23
+ proposed solution — the shape of the fix follows from the shape
24
+ of the problem.
25
+ validations:
26
+ required: true
27
+
28
+ - type: textarea
29
+ id: proposed
30
+ attributes:
31
+ label: Proposed approach
32
+ description: |
33
+ Rough sketch of the change. Modules touched, new data shapes,
34
+ MCP surface changes, config surface changes. Details welcome
35
+ but not required.
36
+ validations:
37
+ required: true
38
+
39
+ - type: textarea
40
+ id: alternatives
41
+ attributes:
42
+ label: Alternatives you considered
43
+ description: What else could solve this, and why the proposed approach wins.
44
+ validations:
45
+ required: false
46
+
47
+ - type: checkboxes
48
+ id: invariants
49
+ attributes:
50
+ label: Which invariants does this touch?
51
+ description: Tick every one this proposal changes or has to preserve.
52
+ options:
53
+ - label: Provenance on every fact
54
+ - label: Audit-first (every request path emits an `AuditRecord`)
55
+ - label: Permission-aware traversal (no node-existence leaks)
56
+ - label: Bitemporal immutability
57
+ - label: Sovereignty (no outbound calls to non-configured hosts)
58
+ - label: Extractor interface stays a drop-in for enclave-scribe
59
+ - label: None of the above
60
+
61
+ - type: dropdown
62
+ id: milestone
63
+ attributes:
64
+ label: Which milestone does this target
65
+ options:
66
+ - "M0 (scaffolding, in-memory storage)"
67
+ - "M1 (Neo4j + extraction wrappers)"
68
+ - "M2 (OpenFGA / persistent audit)"
69
+ - "M3 (planner/executor split, PPR, PathRAG-style pruning)"
70
+ - "M4 (bitemporal writes, ER cascade, connectors)"
71
+ - "v0 GA (design partner ready)"
72
+ - "Not sure — you tell me"
73
+ validations:
74
+ required: true
@@ -0,0 +1,60 @@
1
+ <!--
2
+ Thanks for contributing to Ontos!
3
+
4
+ Please fill in every section below. If a section genuinely doesn't apply,
5
+ write "n/a" and one line saying why — don't delete it.
6
+
7
+ Compliance-critical PRs (anything touching authz, audit, or provenance)
8
+ must include tests under tests/compliance/.
9
+ -->
10
+
11
+ ## Why
12
+
13
+ <!-- The problem this PR solves. Link the issue if one exists (Fixes #NNN). -->
14
+
15
+ ## What
16
+
17
+ <!-- The change, in 3–5 bullets. Reviewers should not have to read the
18
+ diff to know the shape of what changed. -->
19
+
20
+ ## Non-negotiables checklist
21
+
22
+ <!-- Tick every box that applies. If you had to weaken any invariant,
23
+ explain in "Notes for reviewer" below. -->
24
+
25
+ - [ ] Every new `Fact` written to the store carries full `Provenance`.
26
+ - [ ] Every code path that returns data to an agent emits an `AuditRecord` before returning.
27
+ - [ ] No permission post-filtering added; traversal-time checks preserved; no node-existence leaks.
28
+ - [ ] No in-place `Fact` mutation; corrections use `close_fact(...)` supersession.
29
+ - [ ] No outbound network calls to hosts the operator did not configure; no telemetry to Enclave-operated services.
30
+ - [ ] Extractor interface remains a drop-in for `enclave-scribe` — no LlamaIndex/LangChain-specific types leak past `ontos/extraction/`.
31
+
32
+ ## Tests
33
+
34
+ <!-- List what you added/changed under tests/. Compliance-critical PRs
35
+ MUST land with matching tests under tests/compliance/. -->
36
+
37
+ - [ ] Unit tests added / updated
38
+ - [ ] Compliance tests added / updated (required if this touches authz, audit, or provenance)
39
+ - [ ] Integration tests added / updated
40
+ - [ ] Benchmarks updated (if this changes retrieval quality or latency)
41
+
42
+ ## Verification
43
+
44
+ <!-- The exact commands you ran to convince yourself this works. -->
45
+
46
+ ```bash
47
+ uv run ruff check ontos tests
48
+ uv run mypy ontos
49
+ uv run pytest -q
50
+ ```
51
+
52
+ ## Notes for reviewer
53
+
54
+ <!-- Anything the reviewer needs to know that isn't obvious from the diff:
55
+ tradeoffs you considered, alternatives you rejected, follow-ups you
56
+ plan for a later PR. -->
57
+
58
+ ## DCO
59
+
60
+ - [ ] I have signed off every commit (`git commit -s`) per the [DCO](https://developercertificate.org/).
@@ -0,0 +1,67 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main]
6
+ push:
7
+ branches: [main]
8
+ workflow_dispatch:
9
+
10
+ # Cancel superseded runs on the same branch/PR so a fast rebase doesn't
11
+ # leave a stale run consuming a runner.
12
+ concurrency:
13
+ group: ci-${{ github.workflow }}-${{ github.head_ref || github.ref }}
14
+ cancel-in-progress: true
15
+
16
+ permissions:
17
+ contents: read
18
+
19
+ jobs:
20
+ test:
21
+ name: lint · type-check · test
22
+ runs-on: ubuntu-latest
23
+ timeout-minutes: 15
24
+
25
+ steps:
26
+ - name: Checkout
27
+ uses: actions/checkout@v4
28
+
29
+ - name: Install uv
30
+ uses: astral-sh/setup-uv@v3
31
+ with:
32
+ # Cache the uv download index + wheel cache across runs on the
33
+ # same branch. Cache key is derived from uv.lock so a lock
34
+ # change forces a clean install.
35
+ enable-cache: true
36
+ cache-dependency-glob: "uv.lock"
37
+
38
+ - name: Set up Python (from .python-version)
39
+ run: uv python install
40
+
41
+ - name: Install dependencies
42
+ run: uv sync --extra dev --frozen
43
+
44
+ - name: Ruff (lint)
45
+ run: uv run ruff check ontos tests
46
+
47
+ - name: Mypy (strict type-check)
48
+ run: uv run mypy ontos
49
+
50
+ - name: Pytest (unit + compliance)
51
+ run: uv run pytest -q -m "not integration and not benchmark"
52
+
53
+ - name: Pytest (integration — Neo4j via Testcontainers)
54
+ run: uv run pytest -q -m "integration and not benchmark"
55
+
56
+ - name: Set up Helm
57
+ uses: azure/setup-helm@v4
58
+ with:
59
+ version: v3.16.0
60
+
61
+ - name: Helm lint (deploy/helm/ontos)
62
+ run: helm lint deploy/helm/ontos
63
+
64
+ - name: Helm template renders (deploy/helm/ontos)
65
+ # `--dry-run=client` skips the API server; we just want to
66
+ # prove every template compiles into valid YAML.
67
+ run: helm template ontos deploy/helm/ontos > /dev/null
@@ -0,0 +1,173 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+ workflow_dispatch:
8
+ inputs:
9
+ dry_run:
10
+ description: "Build and validate everything; skip PyPI + GHCR pushes."
11
+ type: boolean
12
+ default: true
13
+
14
+ permissions:
15
+ contents: write # for creating the GitHub Release
16
+ packages: write # for pushing to GHCR
17
+ id-token: write # for PyPI trusted publishing (OIDC)
18
+
19
+ concurrency:
20
+ group: release-${{ github.ref }}
21
+ cancel-in-progress: false
22
+
23
+ jobs:
24
+ build:
25
+ name: Build wheels + verify version
26
+ runs-on: ubuntu-latest
27
+ timeout-minutes: 15
28
+ outputs:
29
+ version: ${{ steps.version.outputs.version }}
30
+ steps:
31
+ - name: Checkout
32
+ uses: actions/checkout@v4
33
+
34
+ - name: Install uv
35
+ uses: astral-sh/setup-uv@v3
36
+ with:
37
+ enable-cache: true
38
+ cache-dependency-glob: uv.lock
39
+
40
+ - name: Set up Python
41
+ run: uv python install
42
+
43
+ - name: Extract version from tag
44
+ id: version
45
+ run: |
46
+ if [[ "${{ github.ref }}" == refs/tags/v* ]]; then
47
+ VERSION="${GITHUB_REF#refs/tags/v}"
48
+ else
49
+ # workflow_dispatch: dry-run; use whatever's in _version.py
50
+ VERSION="$(python -c "import runpy; print(runpy.run_path('ontos/_version.py')['__version__'])")"
51
+ fi
52
+ echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
53
+ echo "Building Ontos v${VERSION}"
54
+
55
+ - name: Verify tag matches ontos/_version.py
56
+ if: startsWith(github.ref, 'refs/tags/v')
57
+ run: |
58
+ FILE_VERSION="$(python -c "import runpy; print(runpy.run_path('ontos/_version.py')['__version__'])")"
59
+ TAG_VERSION="${{ steps.version.outputs.version }}"
60
+ if [[ "$FILE_VERSION" != "$TAG_VERSION" ]]; then
61
+ echo "ERROR: git tag v${TAG_VERSION} does not match ontos/_version.py (${FILE_VERSION})"
62
+ exit 1
63
+ fi
64
+
65
+ - name: Build sdist + wheel
66
+ run: uv build
67
+
68
+ - name: Upload build artifacts
69
+ uses: actions/upload-artifact@v4
70
+ with:
71
+ name: dist
72
+ path: dist/
73
+ retention-days: 7
74
+
75
+ publish-pypi:
76
+ name: Publish to PyPI
77
+ needs: build
78
+ runs-on: ubuntu-latest
79
+ if: startsWith(github.ref, 'refs/tags/v') && !inputs.dry_run
80
+ environment:
81
+ name: pypi
82
+ url: https://pypi.org/project/enclave-ontos/${{ needs.build.outputs.version }}
83
+ steps:
84
+ - name: Download build artifacts
85
+ uses: actions/download-artifact@v4
86
+ with:
87
+ name: dist
88
+ path: dist/
89
+
90
+ - name: Publish to PyPI via trusted publishing
91
+ uses: pypa/gh-action-pypi-publish@release/v1
92
+ # No password / API token: uses OIDC trusted publishing. Set up
93
+ # the PyPI project once at pypi.org → Manage → Publishing →
94
+ # Add a new publisher, GitHub, this repo, workflow=release.yml,
95
+ # environment=pypi. See RELEASING.md.
96
+
97
+ publish-ghcr:
98
+ name: Build + push container to GHCR
99
+ needs: build
100
+ runs-on: ubuntu-latest
101
+ if: startsWith(github.ref, 'refs/tags/v') && !inputs.dry_run
102
+ steps:
103
+ - name: Checkout
104
+ uses: actions/checkout@v4
105
+
106
+ - name: Log in to GHCR
107
+ uses: docker/login-action@v3
108
+ with:
109
+ registry: ghcr.io
110
+ username: ${{ github.actor }}
111
+ password: ${{ secrets.GITHUB_TOKEN }}
112
+
113
+ - name: Compute image tags
114
+ id: meta
115
+ run: |
116
+ VERSION="${{ needs.build.outputs.version }}"
117
+ IMAGE="ghcr.io/${{ github.repository_owner }}/ontos"
118
+ # Force lowercase — GHCR requires lowercase image names.
119
+ IMAGE="${IMAGE,,}"
120
+ echo "image=${IMAGE}" >> "$GITHUB_OUTPUT"
121
+ echo "tag_version=${IMAGE}:${VERSION}" >> "$GITHUB_OUTPUT"
122
+ echo "tag_latest=${IMAGE}:latest" >> "$GITHUB_OUTPUT"
123
+
124
+ - name: Build + push image
125
+ uses: docker/build-push-action@v6
126
+ with:
127
+ context: .
128
+ file: deploy/Dockerfile
129
+ push: true
130
+ tags: |
131
+ ${{ steps.meta.outputs.tag_version }}
132
+ ${{ steps.meta.outputs.tag_latest }}
133
+ labels: |
134
+ org.opencontainers.image.source=https://github.com/${{ github.repository }}
135
+ org.opencontainers.image.version=${{ needs.build.outputs.version }}
136
+ org.opencontainers.image.revision=${{ github.sha }}
137
+
138
+ gh-release:
139
+ name: Create GitHub Release
140
+ needs: [build, publish-pypi, publish-ghcr]
141
+ runs-on: ubuntu-latest
142
+ if: startsWith(github.ref, 'refs/tags/v') && !inputs.dry_run
143
+ steps:
144
+ - name: Checkout
145
+ uses: actions/checkout@v4
146
+
147
+ - name: Extract CHANGELOG section for this version
148
+ id: notes
149
+ run: |
150
+ VERSION="${{ needs.build.outputs.version }}"
151
+ # Extract the section between `## [VERSION]` and the next `## [`.
152
+ awk -v v="[$VERSION]" '
153
+ $0 ~ "^## " v { flag=1; next }
154
+ flag && /^## \[/ { flag=0 }
155
+ flag { print }
156
+ ' CHANGELOG.md > release_notes.md
157
+ if [[ ! -s release_notes.md ]]; then
158
+ echo "WARNING: no CHANGELOG section for v${VERSION}; using a stub" >&2
159
+ echo "See CHANGELOG.md for details." > release_notes.md
160
+ fi
161
+
162
+ - name: Download build artifacts
163
+ uses: actions/download-artifact@v4
164
+ with:
165
+ name: dist
166
+ path: dist/
167
+
168
+ - name: Publish GitHub Release
169
+ uses: softprops/action-gh-release@v2
170
+ with:
171
+ body_path: release_notes.md
172
+ files: dist/*
173
+ fail_on_unmatched_files: true
@@ -0,0 +1,24 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ *.egg-info/
5
+ .pytest_cache/
6
+ .mypy_cache/
7
+ .ruff_cache/
8
+ .coverage
9
+ htmlcov/
10
+ .venv/
11
+ venv/
12
+ .env
13
+ .env.*
14
+ !.env.example
15
+ *.db
16
+ *.sqlite
17
+ *.sqlite3
18
+ runtime-data/
19
+ audit-logs/
20
+ .DS_Store
21
+ .idea/
22
+ .vscode/
23
+ dist/
24
+ build/
@@ -0,0 +1 @@
1
+ 3.12