Core changes: - Add @defgroup/@ingroup to 1791 C2+ contracts (555 files) for HCA 128× pre-training DSA grouping - Add §0.1 Pre-Training Frequency matrix to semantics-core - Add §VIII Attention Architecture rules (ATTN_1-4) with MLA/CSA/HCA/DSA mechanics - Add @defgroup/@ingroup to canonical syntax (§II) and all contract examples Agent prompts (5 files): - Add ZERO-STATE RATIONALE with MLA/CSA/HCA/DSA compression mechanics - Add pre-training note: @RATIONALE/@REJECTED are in-context learned tags - svelte-coder: add missing #region contract, fix Svelte rule violations - python-coder/fullstack-coder: honor function contracts from speckit plan - qa-tester: add attention compliance audit (P3 ATTN_1-4 checks) Skills (6 files): - Translate all axiom_config descriptions to English - Fix doc_dirs to index .opencode/ and .specify/ - Deduplicate 5× complexity_rules → single global_tags catalog - Reduce semantics-svelte 591→485 lines (remove duplicate code blocks) - Fix semantics-testing: 'Short IDs' → 'Short hierarchical IDs' - Fix all examples: flat IDs → hierarchical Domain.Name format - Fix Svelte examples: replace raw Tailwind + <button> with semantic tokens + /ui Speckit workflow (commands + templates): - speckit.plan: add Function-Level Contracts for C3+ with @PRE/@POST/@TEST_EDGE - speckit.plan: add Attention Compliance Gate (ATTN_1-4 before contract generation) - speckit.tasks: add function contract inlining format (constraints in task description) - speckit.specify: load semantics-core for spec density rules - spec-template: add #region contract, @SEMANTICS grouping, hierarchical IDs - ux-reference-template: add #region wrapper - plan-template: add attention gate, @defgroup/@ingroup guidance - tasks-template: add attention audit + rebuild + orphan check tasks - constitution.md: translate to English, add Principle VIII (attention-optimized contracts) Reference modules rewritten (hierarchical IDs + full contracts): - Auth.Jwt: 6 child contracts with @RATIONALE/@REJECTED/@TEST_EDGE - Api.Auth: 5 endpoints with @TEST_EDGE + molecular CoT markers - Migration.Model: @defgroup Migration with 18 @ACTION + 6 @INVARIANT Scripts: - add_defgroup_ingroup.py: zero-risk additive @ingroup migration (1791 insertions) - migrate_hierarchical.py: flat→hierarchical ID dry-run analysis (792 contracts) - merge_prompts.py: merge all prompts/skills/commands into one review file Config: - axiom_config.yaml: 749→395 lines (-47%), English, doc_dirs include prompts - Fix test_datasets.py import collision (rename → test_datasets_routes.py) - Fix test_preview.py: SupersetClient→get_superset_client, AsyncMock, logger f-string
75 lines
3.3 KiB
Python
75 lines
3.3 KiB
Python
# #region EncryptionKeyModule [C:5] [TYPE Module] [SEMANTICS encryption, fernet, key, env, secret]
|
|
# @defgroup Core Module group.
|
|
# @BRIEF Resolve a Fernet encryption key from environment or .env file.
|
|
# @LAYER Infrastructure
|
|
# @RELATION DEPENDS_ON -> [LoggerModule]
|
|
# @INVARIANT Runtime key resolution never falls back to an auto-generated key.
|
|
# If no key is found in env or .env, the application crashes early.
|
|
# @PRE ENCRYPTION_KEY is set in process environment or .env file.
|
|
# @POST A valid Fernet key is returned and set in process environment.
|
|
# @SIDE_EFFECT Sets os.environ["ENCRYPTION_KEY"] if loaded from .env file.
|
|
# @DATA_CONTRACT Input[env_file_path] -> Output[encryption_key]
|
|
# @RATIONALE Auto-generating a key on first run is dangerous — the key differs
|
|
# per deployment, making encrypted data unrecoverable on restart.
|
|
# Crash-early forces the admin to explicitly set ENCRYPTION_KEY.
|
|
# @REJECTED Auto-generation rejected — encrypted data becomes unrecoverable
|
|
# when the key changes between deployments (see [SEC:H-3]).
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from pathlib import Path
|
|
|
|
from cryptography.fernet import Fernet
|
|
|
|
from .logger import belief_scope, logger
|
|
|
|
DEFAULT_ENV_FILE_PATH = Path(__file__).resolve().parents[2] / ".env"
|
|
|
|
|
|
# #region ensure_encryption_key [TYPE Function]
|
|
# @ingroup Core
|
|
# @BRIEF Ensure backend runtime has a persistent valid Fernet key.
|
|
# @PRE ENCRYPTION_KEY is set in process environment or backend/.env file.
|
|
# @POST Returns a valid Fernet key and sets it in process environment.
|
|
# @SIDE_EFFECT Sets os.environ["ENCRYPTION_KEY"] if loaded from .env file.
|
|
# @RAISES RuntimeError if no ENCRYPTION_KEY is found anywhere.
|
|
def ensure_encryption_key(env_file_path: Path = DEFAULT_ENV_FILE_PATH) -> str:
|
|
with belief_scope("ensure_encryption_key", f"env_file_path={env_file_path}"):
|
|
|
|
# 1. Check process environment
|
|
existing_key = os.getenv("ENCRYPTION_KEY", "").strip()
|
|
if existing_key:
|
|
Fernet(existing_key.encode())
|
|
logger.reason("Using ENCRYPTION_KEY from process environment.")
|
|
return existing_key
|
|
|
|
# 2. Check .env file
|
|
if env_file_path.exists():
|
|
for raw_line in env_file_path.read_text(encoding="utf-8").splitlines():
|
|
if raw_line.startswith("ENCRYPTION_KEY="):
|
|
persisted_key = raw_line.partition("=")[2].strip()
|
|
if persisted_key:
|
|
Fernet(persisted_key.encode())
|
|
os.environ["ENCRYPTION_KEY"] = persisted_key
|
|
logger.reason(f"Loaded ENCRYPTION_KEY from {env_file_path}.")
|
|
return persisted_key
|
|
|
|
# 3. Crash-early — no auto-generation (see [SEC:H-3])
|
|
logger.explore(
|
|
"No ENCRYPTION_KEY found in environment or .env file. "
|
|
"Generate one with: python -c \"from cryptography.fernet import Fernet; "
|
|
"print(Fernet.generate_key().decode())\" and set it in .env or export it."
|
|
)
|
|
raise RuntimeError(
|
|
"ENCRYPTION_KEY is not set. "
|
|
"Generate a key and add it to your .env file:\n"
|
|
" python -c \"from cryptography.fernet import Fernet; "
|
|
"print(Fernet.generate_key().decode())\""
|
|
)
|
|
|
|
|
|
# #endregion ensure_encryption_key
|
|
|
|
# #endregion EncryptionKeyModule
|