commit f6e8957a2eeaf846303182d07dd5fda5521e20bd Author: Albrecht Degering Date: Thu Jul 30 17:42:10 2026 +0200 feat: scaffold encryption capability boundaries diff --git a/.gitea/ISSUE_TEMPLATE/bug_report.md b/.gitea/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..7db9b09 --- /dev/null +++ b/.gitea/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,35 @@ +--- +name: "Bug" +about: "Report a reproducible defect, regression, or incorrect behavior" +title: "[Bug] " +labels: + - type/bug + - status/triage + - module/encryption +--- + +## Scope + +- Repository: +- Area/module: +- Affected version or commit: + +## Behavior + +Expected: + +Actual: + +## Reproduction + +1. +2. +3. + +## Evidence + +Logs, screenshots, traces, or failing test output: + +## Verification Target + +Command or workflow that should pass when fixed: diff --git a/.gitea/ISSUE_TEMPLATE/config.yaml b/.gitea/ISSUE_TEMPLATE/config.yaml new file mode 100644 index 0000000..3ba13e0 --- /dev/null +++ b/.gitea/ISSUE_TEMPLATE/config.yaml @@ -0,0 +1 @@ +blank_issues_enabled: false diff --git a/.gitea/ISSUE_TEMPLATE/docs_workflow.md b/.gitea/ISSUE_TEMPLATE/docs_workflow.md new file mode 100644 index 0000000..1b6866f --- /dev/null +++ b/.gitea/ISSUE_TEMPLATE/docs_workflow.md @@ -0,0 +1,27 @@ +--- +name: "Docs / workflow" +about: "Request documentation, process, or developer workflow changes" +title: "[Docs] " +labels: + - type/docs + - status/triage + - module/encryption + - area/docs +--- + +## Scope + +- Repository: +- Document or workflow: + +## Current State + +What is missing, unclear, duplicated, or stale? + +## Desired State + +What should the docs or workflow make clear? + +## Verification Target + +How should this be checked? diff --git a/.gitea/ISSUE_TEMPLATE/feature_request.md b/.gitea/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..de88876 --- /dev/null +++ b/.gitea/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,32 @@ +--- +name: "Feature" +about: "Propose new user-visible behavior or platform capability" +title: "[Feature] " +labels: + - type/feature + - status/triage + - module/encryption +--- + +## Problem + +What user, operator, or developer problem should this solve? + +## Proposed Capability + +What should exist when this is done? + +## Ownership + +- Owning repository: +- Related module repositories: +- Extension point or integration boundary: + +## Acceptance Criteria + +- [ ] +- [ ] + +## Verification Target + +Command, scenario, or UI flow that should prove completion: diff --git a/.gitea/ISSUE_TEMPLATE/task.md b/.gitea/ISSUE_TEMPLATE/task.md new file mode 100644 index 0000000..8eac298 --- /dev/null +++ b/.gitea/ISSUE_TEMPLATE/task.md @@ -0,0 +1,28 @@ +--- +name: "Task" +about: "Track implementation, maintenance, or migration work" +title: "[Task] " +labels: + - type/task + - status/triage + - module/encryption +--- + +## Objective + +What needs to be completed? + +## Scope + +- Owning repository: +- In-scope: +- Out-of-scope: + +## Checklist + +- [ ] +- [ ] + +## Verification Target + +Command or manual check: diff --git a/.gitea/ISSUE_TEMPLATE/tech_debt.md b/.gitea/ISSUE_TEMPLATE/tech_debt.md new file mode 100644 index 0000000..bdc9620 --- /dev/null +++ b/.gitea/ISSUE_TEMPLATE/tech_debt.md @@ -0,0 +1,25 @@ +--- +name: "Tech debt" +about: "Track cleanup, refactoring, risk reduction, or deferred engineering work" +title: "[Debt] " +labels: + - type/debt + - status/triage + - module/encryption +--- + +## Current Cost + +What does this make harder, riskier, slower, or more fragile? + +## Desired Shape + +What should the code, tests, or architecture look like afterwards? + +## Constraints + +What behavior, compatibility, or module boundary must be preserved? + +## Verification Target + +Focused checks that should pass: diff --git a/.gitea/PULL_REQUEST_TEMPLATE.md b/.gitea/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..1984736 --- /dev/null +++ b/.gitea/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,15 @@ +## Issue + +Closes # + +## Summary + +- + +## Verification + +- + +## Notes + +Follow-up issues: diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..252e52a --- /dev/null +++ b/.gitignore @@ -0,0 +1,353 @@ +# ---> Node +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# vitepress build output +**/.vitepress/dist + +# vitepress cache directory +**/.vitepress/cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# Local WebUI test/build scratch directories +.component-test-build/ +.file-drop-test-build/ +.module-test-build/ +.policy-test-build/ +.template-preview-test-build/ +.import-test-build/ +webui/.component-test-build/ +webui/.file-drop-test-build/ +webui/.module-test-build/ +webui/.policy-test-build/ +webui/.template-preview-test-build/ +webui/.import-test-build/ + +# Security audit reports +audit-reports/ + +# ---> Python +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# UV +# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +#uv.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/latest/usage/project/#working-with-version-control +.pdm.toml +.pdm-python +.pdm-build/ + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +# Ruff stuff: +.ruff_cache/ + +# PyPI configuration file +.pypirc + +# ---> VisualStudioCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +*.db + +# GovOPlaN local runtime state +runtime/ + +# GovOPlaN WebUI test output +webui/.module-test-build/ +webui/.component-test-build/ diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..54d21f2 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,21 @@ +# GovOPlaN Encryption Codex Guide + +## Scope + +This repository owns optional cryptographic platform capabilities: vaults, key +hierarchies, content-protection profiles, E2EE recipient and device keys, +rotation, recovery ceremonies, and disable/uninstall assurance. + +## Boundaries + +- Core owns neutral capability contracts and module discovery. +- Feature modules own plaintext semantics, authorization, retention, and normal + resource ownership. +- This module may protect feature-owned payloads but must not become their + business-data store. +- Never add placeholder, home-grown, or unauthenticated cryptography. +- A disable or uninstall operation must prove that every protection reference + was decrypted, rewrapped, explicitly exported, or cryptographically deleted. +- Ownership recovery and cryptographic key recovery are separate processes. + +Use Gitea issues as the canonical backlog and state log. diff --git a/README.md b/README.md new file mode 100644 index 0000000..d5d9685 --- /dev/null +++ b/README.md @@ -0,0 +1,53 @@ +# GovOPlaN Encryption + + +**Repository type:** module (platform). + + +`govoplan-encryption` is the optional platform boundary for managed key vaults, +content encryption, end-to-end encryption profiles, key rotation, recovery, and +cryptographic deletion assurance. + +The module is deliberately scaffolded before cryptographic implementation. It +announces stable integration surfaces and policy boundaries without presenting +placeholder cryptography as production-ready protection. + +## Boundary + +The module will own: + +- vault and key hierarchy metadata +- envelope-key wrapping and rotation workflows +- content-protection profiles, including E2EE profiles +- device and recipient key registration +- recovery ceremonies, assurance evidence, and key custody +- disable and uninstall preflight for protected content + +Feature modules continue to own their content, authorization, retention, and +normal ownership records. They integrate through optional encryption +capabilities and store only stable protection references and ciphertext. + +## Disable Rule + +Disabling or uninstalling this module must never make protected content silently +unreadable. Every protected object must first be decrypted, rewrapped to another +available provider, exported with explicit key custody, or deliberately +destroyed under an authorized cryptographic-deletion process. The eventual +uninstall guard will block while unresolved protection references remain. + +See [docs/ENCRYPTION_BOUNDARY.md](docs/ENCRYPTION_BOUNDARY.md) for the initial +threat, ownership, recovery, and lifecycle decisions. + +## Current State + +The repository currently contains a discoverable manifest, permission and role +metadata, versioned interface announcements, documentation, and focused tests. +It has no routes, persistence, WebUI, key generation, or encryption runtime yet. + +## Verification + +```bash +cd /mnt/DATA/git/govoplan-encryption +PYTHONPATH=src:/mnt/DATA/git/govoplan-core/src \ + /mnt/DATA/git/govoplan/.venv/bin/python -m unittest discover -s tests +``` diff --git a/docs/ENCRYPTION_BOUNDARY.md b/docs/ENCRYPTION_BOUNDARY.md new file mode 100644 index 0000000..d7a2def --- /dev/null +++ b/docs/ENCRYPTION_BOUNDARY.md @@ -0,0 +1,50 @@ +# Encryption Boundary + +## Purpose + +`govoplan-encryption` is an optional cryptographic service module. It supplies +key and content-protection capabilities to modules that choose to use them. It +does not own feature data, normal authorization, retention, or business +ownership. + +## Initial Invariants + +1. Resource ownership and cryptographic key custody are independent. +2. Administrative ownership recovery does not grant encryption keys. +3. Key recovery is a separate, high-assurance, auditable ceremony. +4. Every ciphertext carries a stable protection profile, key version, algorithm + suite, and authenticated context reference. +5. Rotation and rewrapping are resumable and idempotent. +6. Protected content cannot silently fall back to plaintext. +7. Provider loss, disabled modules, unavailable devices, and recovery delay are + visible states, not generic read failures. +8. Disabling or uninstalling is blocked while unresolved protected content + remains. + +## Planned Capability Families + +- **Key vault:** create and resolve key hierarchies without exposing raw key + material to feature modules. +- **Content protection:** authenticated envelope encryption and decryption for + authorized feature-owned payloads. +- **E2EE profiles:** recipient/device key envelopes where the server cannot + decrypt normal content. +- **Rotation:** rewrap keys and migrate algorithm suites with bounded progress + and evidence. +- **Recovery ceremony:** quorum, delay, recent authentication, custody evidence, + and explicit scope. +- **Disable preflight:** inventory protection references and produce a blocking + migration plan. + +## Decisions Deferred Until Threat Modeling + +- cryptographic libraries and external KMS/HSM providers +- server-managed versus client-managed profile suites +- per-object, per-vault, and per-recipient data-key granularity +- device enrollment and revocation protocol +- external-recipient key discovery and trust +- recovery quorum defaults for each assurance profile +- ciphertext portability and offline export format + +These decisions require explicit threat models and interoperability fixtures. +They must not be inferred from ordinary resource-ownership workflows. diff --git a/docs/gitea-labels.json b/docs/gitea-labels.json new file mode 100644 index 0000000..775a288 --- /dev/null +++ b/docs/gitea-labels.json @@ -0,0 +1,548 @@ +[ + { + "name": "type/bug", + "color": "d73a4a", + "description": "A reproducible defect, regression, or incorrect behavior.", + "exclusive": true + }, + { + "name": "type/feature", + "color": "0e8a16", + "description": "New user-visible behavior or platform capability.", + "exclusive": true + }, + { + "name": "type/user-story", + "color": "1d76db", + "description": "End-to-end user journey or real-world process story used to steer product slices.", + "exclusive": true + }, + { + "name": "type/task", + "color": "1d76db", + "description": "Implementation, maintenance, migration, or operational work.", + "exclusive": true + }, + { + "name": "type/debt", + "color": "fbca04", + "description": "Cleanup, refactoring, risk reduction, or deferred engineering work.", + "exclusive": true + }, + { + "name": "type/docs", + "color": "5319e7", + "description": "Documentation, process, or developer workflow work.", + "exclusive": true + }, + { + "name": "priority/p0", + "color": "b60205", + "description": "Immediate stop-the-line priority.", + "exclusive": true + }, + { + "name": "priority/p1", + "color": "d93f0b", + "description": "High priority for the next focused work window.", + "exclusive": true + }, + { + "name": "priority/p2", + "color": "fbca04", + "description": "Normal planned priority.", + "exclusive": true + }, + { + "name": "priority/p3", + "color": "c2e0c6", + "description": "Low priority or opportunistic cleanup.", + "exclusive": true + }, + { + "name": "status/triage", + "color": "d4c5f9", + "description": "Needs review, ownership, priority, or acceptance criteria.", + "exclusive": true + }, + { + "name": "status/ready", + "color": "0e8a16", + "description": "Ready for implementation.", + "exclusive": true + }, + { + "name": "status/in-progress", + "color": "0052cc", + "description": "Currently being worked.", + "exclusive": true + }, + { + "name": "status/blocked", + "color": "b60205", + "description": "Cannot progress without a decision, dependency, credential, or external change.", + "exclusive": true + }, + { + "name": "status/needs-info", + "color": "f9d0c4", + "description": "Needs clarifying input before implementation can proceed safely.", + "exclusive": true + }, + { + "name": "module/access", + "color": "0e8a16", + "description": "GovOPlaN access, identity, authentication, RBAC, and administration behavior.", + "exclusive": false + }, + { + "name": "module/addresses", + "color": "5319e7", + "description": "GovOPlaN Addresses module behavior or integration.", + "exclusive": false + }, + { + "name": "module/admin", + "color": "006b75", + "description": "GovOPlaN Admin module behavior or integration.", + "exclusive": false + }, + { + "name": "module/appointments", + "color": "d876e3", + "description": "GovOPlaN Appointments module behavior or integration.", + "exclusive": false + }, + { + "name": "module/audit", + "color": "0e8a16", + "description": "GovOPlaN Audit module behavior or integration.", + "exclusive": false + }, + { + "name": "module/calendar", + "color": "bfd4f2", + "description": "GovOPlaN Calendar module behavior or integration.", + "exclusive": false + }, + { + "name": "module/campaign", + "color": "d876e3", + "description": "GovOPlaN campaign module behavior or integration.", + "exclusive": false + }, + { + "name": "module/cases", + "color": "1d76db", + "description": "GovOPlaN Cases module behavior or integration.", + "exclusive": false + }, + { + "name": "module/connectors", + "color": "c2e0c6", + "description": "GovOPlaN Connectors module behavior or integration.", + "exclusive": false + }, + { + "name": "module/core", + "color": "0052cc", + "description": "GovOPlaN core runner, shared primitives, shell, or extension points.", + "exclusive": false + }, + { + "name": "module/dashboard", + "color": "1d76db", + "description": "GovOPlaN Dashboard module behavior or integration.", + "exclusive": false + }, + { + "name": "module/dataflow", + "color": "1d76db", + "description": "GovOPlaN Dataflow module behavior or integration.", + "exclusive": false + }, + { + "name": "module/datasources", + "color": "006b75", + "description": "GovOPlaN governed datasource contracts, catalogs, and integrations.", + "exclusive": false + }, + { + "name": "module/dms", + "color": "c5def5", + "description": "GovOPlaN Dms module behavior or integration.", + "exclusive": false + }, + { + "name": "module/docs", + "color": "c5def5", + "description": "GovOPlaN Docs module behavior or integration.", + "exclusive": false + }, + { + "name": "module/dist-lists", + "color": "0e8a16", + "description": "GovOPlaN Distribution Lists module behavior or integration.", + "exclusive": false + }, + { + "name": "module/erp", + "color": "fef2c0", + "description": "GovOPlaN Erp module behavior or integration.", + "exclusive": false + }, + { + "name": "module/evaluation", + "color": "bfdadc", + "description": "GovOPlaN Evaluation module behavior or integration.", + "exclusive": false + }, + { + "name": "module/files", + "color": "006b75", + "description": "GovOPlaN files module behavior or integration.", + "exclusive": false + }, + { + "name": "module/fit-connect", + "color": "fbca04", + "description": "GovOPlaN Fit Connect module behavior or integration.", + "exclusive": false + }, + { + "name": "module/forms", + "color": "f9d0c4", + "description": "GovOPlaN Forms module behavior or integration.", + "exclusive": false + }, + { + "name": "module/helpdesk", + "color": "c2e0c6", + "description": "GovOPlaN Helpdesk module behavior or integration.", + "exclusive": false + }, + { + "name": "module/identity-trust", + "color": "d4c5f9", + "description": "GovOPlaN Identity Trust module behavior or integration.", + "exclusive": false + }, + { + "name": "module/identity", + "color": "bfd4f2", + "description": "GovOPlaN Identity module behavior or integration.", + "exclusive": false + }, + { + "name": "module/idm", + "color": "0052cc", + "description": "GovOPlaN Idm module behavior or integration.", + "exclusive": false + }, + { + "name": "module/ledger", + "color": "5319e7", + "description": "GovOPlaN Ledger module behavior or integration.", + "exclusive": false + }, + { + "name": "module/mail", + "color": "5319e7", + "description": "GovOPlaN mail module behavior or integration.", + "exclusive": false + }, + { + "name": "module/notifications", + "color": "d876e3", + "description": "GovOPlaN Notifications module behavior or integration.", + "exclusive": false + }, + { + "name": "module/ops", + "color": "0e8a16", + "description": "GovOPlaN Ops module behavior or integration.", + "exclusive": false + }, + { + "name": "module/organizations", + "color": "bfdadc", + "description": "GovOPlaN Organizations module behavior or integration.", + "exclusive": false + }, + { + "name": "module/payments", + "color": "bfd4f2", + "description": "GovOPlaN Payments module behavior or integration.", + "exclusive": false + }, + { + "name": "module/permits", + "color": "fbca04", + "description": "GovOPlaN Permits module behavior or integration.", + "exclusive": false + }, + { + "name": "module/policy", + "color": "d93f0b", + "description": "GovOPlaN Policy module behavior or integration.", + "exclusive": false + }, + { + "name": "module/poll", + "color": "e4e669", + "description": "GovOPlaN Poll module behavior or integration.", + "exclusive": false + }, + { + "name": "module/portal", + "color": "1d76db", + "description": "GovOPlaN Portal module behavior or integration.", + "exclusive": false + }, + { + "name": "module/postbox", + "color": "d93f0b", + "description": "GovOPlaN Postbox module behavior or integration.", + "exclusive": false + }, + { + "name": "module/projects", + "color": "5319e7", + "description": "GovOPlaN Projects module behavior or integration.", + "exclusive": false + }, + { + "name": "module/reporting", + "color": "c2e0c6", + "description": "GovOPlaN Reporting module behavior or integration.", + "exclusive": false + }, + { + "name": "module/risk-compliance", + "color": "b60205", + "description": "GovOPlaN Risk Compliance module behavior or integration.", + "exclusive": false + }, + { + "name": "module/search", + "color": "bfdadc", + "description": "GovOPlaN Search module behavior or integration.", + "exclusive": false + }, + { + "name": "module/scheduling", + "color": "d93f0b", + "description": "GovOPlaN Scheduling module behavior or integration.", + "exclusive": false + }, + { + "name": "module/tasks", + "color": "c5def5", + "description": "GovOPlaN Tasks module behavior or integration.", + "exclusive": false + }, + { + "name": "module/templates", + "color": "fef2c0", + "description": "GovOPlaN Templates module behavior or integration.", + "exclusive": false + }, + { + "name": "module/tenancy", + "color": "e4e669", + "description": "GovOPlaN Tenancy module behavior or integration.", + "exclusive": false + }, + { + "name": "module/tickets", + "color": "0e8a16", + "description": "GovOPlaN Tickets module behavior or integration.", + "exclusive": false + }, + { + "name": "module/views", + "color": "c5def5", + "description": "GovOPlaN governed task views, interface projections, and workflow view integration.", + "exclusive": false + }, + { + "name": "module/wiki", + "color": "006b75", + "description": "GovOPlaN Wiki module behavior or integration.", + "exclusive": false + }, + { + "name": "module/workflow", + "color": "f9d0c4", + "description": "GovOPlaN Workflow module behavior or integration.", + "exclusive": false + }, + { + "name": "module/xoev", + "color": "d4c5f9", + "description": "GovOPlaN Xoev module behavior or integration.", + "exclusive": false + }, + { + "name": "module/xrechnung", + "color": "0052cc", + "description": "GovOPlaN Xrechnung module behavior or integration.", + "exclusive": false + }, + { + "name": "module/xta-osci", + "color": "5319e7", + "description": "GovOPlaN Xta Osci module behavior or integration.", + "exclusive": false + }, + { + "name": "area/auth", + "color": "bfd4f2", + "description": "Authentication, sessions, access bootstrap, or login behavior.", + "exclusive": false + }, + { + "name": "area/tenancy", + "color": "bfdadc", + "description": "Tenant boundaries, provisioning, or tenant-scoped data behavior.", + "exclusive": false + }, + { + "name": "area/rbac", + "color": "c5def5", + "description": "Permissions, roles, delegation, or authorization policy.", + "exclusive": false + }, + { + "name": "area/governance", + "color": "fef2c0", + "description": "Governance policy, audit, privacy, retention, or compliance behavior.", + "exclusive": false + }, + { + "name": "area/module-system", + "color": "bfe5bf", + "description": "Module discovery, manifests, capabilities, routing, or optional integrations.", + "exclusive": false + }, + { + "name": "area/migrations", + "color": "e4e669", + "description": "Alembic migrations, schema bootstrap, or persistence evolution.", + "exclusive": false + }, + { + "name": "area/webui", + "color": "1d76db", + "description": "Shared WebUI shell, frontend components, routing, or frontend tests.", + "exclusive": false + }, + { + "name": "area/api", + "color": "5319e7", + "description": "HTTP API contracts, routers, schemas, or API smoke behavior.", + "exclusive": false + }, + { + "name": "area/db", + "color": "0e8a16", + "description": "Database sessions, models, transactions, or persistence primitives.", + "exclusive": false + }, + { + "name": "area/devex", + "color": "bfd4f2", + "description": "Local developer workflow, scripts, tests, tooling, or release helpers.", + "exclusive": false + }, + { + "name": "area/release", + "color": "c2e0c6", + "description": "Versioning, release locks, tags, packaging, or dependency pins.", + "exclusive": false + }, + { + "name": "area/security", + "color": "b60205", + "description": "Security posture, static analysis, supply-chain hardening, or vulnerability remediation.", + "exclusive": false + }, + { + "name": "area/docs", + "color": "5319e7", + "description": "Durable documentation and project guidance.", + "exclusive": false + }, + { + "name": "area/marketing", + "color": "f9d0c4", + "description": "Public website, product messaging, publication copy, or legal page content.", + "exclusive": false + }, + { + "name": "source/todo-scan", + "color": "cccccc", + "description": "Imported from inline TODO/FIXME/HACK markers by the Gitea TODO importer.", + "exclusive": false + }, + { + "name": "source/backlog-import", + "color": "bfdadc", + "description": "Imported from markdown backlog, roadmap, plan, or TODO files.", + "exclusive": false + }, + { + "name": "source/security-audit", + "color": "d4c5f9", + "description": "Created from a structured security or code-quality audit report.", + "exclusive": false + }, + { + "name": "audit/quick-fix", + "color": "0e8a16", + "description": "Audit finding that appears narrow and directly fixable.", + "exclusive": false + }, + { + "name": "audit/structural", + "color": "d93f0b", + "description": "Audit finding that needs design, refactoring, or behavior review.", + "exclusive": false + }, + { + "name": "audit/complexity", + "color": "fbca04", + "description": "Complexity finding from Radon, Xenon, or equivalent maintainability scans.", + "exclusive": false + }, + { + "name": "audit/duplication", + "color": "c2e0c6", + "description": "Duplicated-code finding from jscpd or equivalent similarity scans.", + "exclusive": false + }, + { + "name": "audit/false-positive", + "color": "cccccc", + "description": "Audit finding reviewed as a narrow false positive or acceptable risk.", + "exclusive": false + }, + { + "name": "audit/needs-design", + "color": "f9d0c4", + "description": "Audit finding that needs an architectural or product decision before implementation.", + "exclusive": false + }, + { + "name": "codex/ready", + "color": "0e8a16", + "description": "Suitable for Codex to pick up with the existing issue context.", + "exclusive": false + }, + { + "name": "codex/needs-human", + "color": "f9d0c4", + "description": "Needs an explicit human decision before Codex should implement.", + "exclusive": false + } +] diff --git a/package.json b/package.json new file mode 100644 index 0000000..0883047 --- /dev/null +++ b/package.json @@ -0,0 +1,8 @@ +{ + "name": "@govoplan/encryption", + "version": "0.1.14", + "private": true, + "description": "GovOPlaN encryption platform module scaffold.", + "type": "module", + "peerDependencies": {} +} diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..484b7a5 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,22 @@ +[build-system] +requires = ["setuptools>=69", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "govoplan-encryption" +version = "0.1.14" +description = "Optional key-vault and content-protection capabilities for GovOPlaN." +readme = "README.md" +requires-python = ">=3.12" +license = "AGPL-3.0-or-later" +authors = [{ name = "GovOPlaN" }] +dependencies = ["govoplan-core>=0.1.14"] + +[tool.setuptools.packages.find] +where = ["src"] + +[tool.setuptools.package-data] +govoplan_encryption = ["py.typed"] + +[project.entry-points."govoplan.modules"] +encryption = "govoplan_encryption.backend.manifest:get_manifest" diff --git a/src/govoplan_encryption/__init__.py b/src/govoplan_encryption/__init__.py new file mode 100644 index 0000000..c8dbe81 --- /dev/null +++ b/src/govoplan_encryption/__init__.py @@ -0,0 +1,5 @@ +"""GovOPlaN encryption platform module.""" + +from govoplan_encryption.backend.manifest import get_manifest + +__all__ = ["get_manifest"] diff --git a/src/govoplan_encryption/backend/__init__.py b/src/govoplan_encryption/backend/__init__.py new file mode 100644 index 0000000..4714ac5 --- /dev/null +++ b/src/govoplan_encryption/backend/__init__.py @@ -0,0 +1 @@ +"""Backend integration surface for govoplan-encryption.""" diff --git a/src/govoplan_encryption/backend/manifest.py b/src/govoplan_encryption/backend/manifest.py new file mode 100644 index 0000000..1c1c0ee --- /dev/null +++ b/src/govoplan_encryption/backend/manifest.py @@ -0,0 +1,142 @@ +from __future__ import annotations + +from govoplan_core.core.modules import ( + DocumentationTopic, + ModuleInterfaceProvider, + ModuleManifest, + PermissionDefinition, + RoleTemplate, +) + + +MODULE_ID = "encryption" +MODULE_NAME = "Encryption" +MODULE_VERSION = "0.1.14" + +USE_SCOPE = "encryption:vault:use" +ADMIN_SCOPE = "encryption:vault:admin" +RECOVERY_SCOPE = "encryption:recovery:approve" + +OPTIONAL_DEPENDENCIES = ( + "access", + "audit", + "policy", + "notifications", + "files", + "postbox", + "campaigns", + "workflow", +) + + +def _permission( + scope: str, + label: str, + description: str, +) -> PermissionDefinition: + module_id, resource, action = scope.split(":", 2) + return PermissionDefinition( + scope=scope, + label=label, + description=description, + category="Encryption", + level="tenant", + module_id=module_id, + resource=resource, + action=action, + ) + + +PERMISSIONS = ( + _permission( + USE_SCOPE, + "Use encryption profiles", + "Protect and decrypt authorized content through an available profile.", + ), + _permission( + ADMIN_SCOPE, + "Administer encryption", + "Manage vaults, protection profiles, key rotation, and provider policy.", + ), + _permission( + RECOVERY_SCOPE, + "Approve key recovery", + "Participate in an auditable recovery ceremony without gaining content ownership.", + ), +) + +ROLE_TEMPLATES = ( + RoleTemplate( + slug="encryption_user", + name="Encryption user", + description="Use configured content-protection profiles.", + permissions=(USE_SCOPE,), + ), + RoleTemplate( + slug="encryption_custodian", + name="Encryption custodian", + description="Administer encryption and participate in key recovery.", + permissions=(USE_SCOPE, ADMIN_SCOPE, RECOVERY_SCOPE), + ), +) + +manifest = ModuleManifest( + id=MODULE_ID, + name=MODULE_NAME, + version=MODULE_VERSION, + optional_dependencies=OPTIONAL_DEPENDENCIES, + provides_interfaces=( + ModuleInterfaceProvider(name="encryption.key_vault", version="1.0.0"), + ModuleInterfaceProvider( + name="encryption.content_protection", + version="1.0.0", + ), + ModuleInterfaceProvider( + name="encryption.recovery_ceremony", + version="1.0.0", + ), + ModuleInterfaceProvider( + name="encryption.disable_preflight", + version="1.0.0", + ), + ), + permissions=PERMISSIONS, + role_templates=ROLE_TEMPLATES, + documentation=( + DocumentationTopic( + id="encryption.boundary", + title="Encryption and key-custody boundary", + summary=( + "Optional vault, content-protection, rotation, recovery, and " + "disable-assurance capabilities." + ), + body=( + "Encryption protects feature-owned content without taking over " + "its business ownership. Resource ownership recovery never " + "implicitly grants cryptographic keys. Disabling the module is " + "blocked until protected objects are decrypted, rewrapped, " + "explicitly exported, or cryptographically deleted." + ), + layer="available", + documentation_types=("admin",), + audience=("administrator", "security_officer", "product_owner"), + related_modules=OPTIONAL_DEPENDENCIES, + order=100, + ), + ), +) + + +def get_manifest() -> ModuleManifest: + return manifest + + +__all__ = [ + "ADMIN_SCOPE", + "MODULE_ID", + "MODULE_VERSION", + "RECOVERY_SCOPE", + "USE_SCOPE", + "get_manifest", + "manifest", +] diff --git a/src/govoplan_encryption/py.typed b/src/govoplan_encryption/py.typed new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/govoplan_encryption/py.typed @@ -0,0 +1 @@ + diff --git a/tests/test_manifest.py b/tests/test_manifest.py new file mode 100644 index 0000000..5307a71 --- /dev/null +++ b/tests/test_manifest.py @@ -0,0 +1,39 @@ +from __future__ import annotations + +import unittest + +from govoplan_encryption.backend.manifest import ( + ADMIN_SCOPE, + RECOVERY_SCOPE, + USE_SCOPE, + get_manifest, +) + + +class EncryptionManifestTests(unittest.TestCase): + def test_manifest_is_an_optional_contract_only_seed(self) -> None: + manifest = get_manifest() + + self.assertEqual(manifest.id, "encryption") + self.assertEqual(manifest.dependencies, ()) + self.assertIn("access", manifest.optional_dependencies) + self.assertEqual( + {permission.scope for permission in manifest.permissions}, + {USE_SCOPE, ADMIN_SCOPE, RECOVERY_SCOPE}, + ) + self.assertEqual( + {provider.name for provider in manifest.provides_interfaces}, + { + "encryption.key_vault", + "encryption.content_protection", + "encryption.recovery_ceremony", + "encryption.disable_preflight", + }, + ) + self.assertIsNone(manifest.route_factory) + self.assertIsNone(manifest.migration_spec) + self.assertIsNone(manifest.frontend) + + +if __name__ == "__main__": + unittest.main()