CA/PKI Backend Project Context (Updated) Stack Python 3 + psycopg (dict_row cursors) PostgreSQL database: ca Unit tests: unittest Run via: python3 -m unittest discover Current test count: 17 Database Schema (current assumptions) entity id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY creation_ts TIMESTAMPTZ DEFAULT now() creator INT FK → entity(id) (nullable) name VARCHAR(100) NOT NULL type VARCHAR(...) NOT NULL Allowed types: person, group, device public_key VARCHAR(300) NOT NULL symmetrical_key VARCHAR(100) NULL status VARCHAR(...) NOT NULL DEFAULT 'active' Values: 'active', 'revoked' expiration DATE NULL ca_reference VARCHAR(100) NULL Constraint CHECK ( (type = 'group' AND ca_reference IS NOT NULL) OR (type <> 'group' AND ca_reference IS NULL) ) Rule: Groups MUST have a ca_reference All other entity types MUST have ca_reference IS NULL Indexes: Index on entity(name) Other indexes as needed group_member group_id INT FK → entity(id) ON DELETE CASCADE member_id INT FK → entity(id) ON DELETE CASCADE role VARCHAR(10) PRIMARY KEY (group_id, member_id) Index (member_id, group_id) Groups can contain: persons devices other groups property id INT FK → entity(id) ON DELETE CASCADE property_name VARCHAR(100) NOT NULL validation_policy CHAR(19) NOT NULL DEFAULT 'default' source VARCHAR(150) NULL PRIMARY KEY (id, property_name) Notes: validation_policy is CHAR(19) and padded by PostgreSQL. Used for flags/roles such as "creator". metadata Singleton row table (enforced at application level). Columns: name comment private_key public_key defense_p BOOLEAN NOT NULL DEFAULT false defense_p: Global system flag. Logged on change. log id SERIAL PRIMARY KEY ts TIMESTAMPTZ DEFAULT now() entry TEXT NOT NULL Every API mutation must insert exactly one row here. Core Business Rules Creators are NOT an entity type "creator" is a property (property_name='creator') on a person. insert_creator(): Creates a person Adds "creator" property Revoked entities are immutable All entity mutations must call: ensure_entity_active(cursor, entity_id) Revoked entities CANNOT: Join groups Accept members Add/delete properties Change public_key Change symmetrical_key Change status again Group CA Reference Rule group entities must include a non-null ca_reference. person and device must not define ca_reference. Enforced at: Database level (CHECK constraint) Python validation level Property Metadata Each property includes: validation_policy source Defaults: validation_policy = 'default' source = NULL Property mutations: Require entity to be active Must log changes Metadata Defense Flag defense_p: Boolean system-wide flag Default: false Must be logged when changed Logging Rules All changes to: entity group_member property metadata Must call: log_change(cursor, "...") Logging: Happens inside same transaction No extra commits Exactly one log row per mutation Python Modules ca_core/entity.py Provides: ensure_entity_active(cursor, entity_id) insert_creator(cursor, name, public_key) enroll_person(cursor, name, public_key, creator_id) create_group(cursor, name, public_key, creator_id, ca_reference) get_entity(cursor, entity_id) set_entity_status(cursor, entity_id, status, changed_by) set_entity_keys(cursor, entity_id, public_key, changed_by) set_symmetrical_key(cursor, entity_id, key, changed_by) get_symmetrical_key(cursor, entity_id) ca_core/group_member.py Uses member_id Prevents adding revoked groups/members Logs membership add/remove ca_core/property.py Table: property(id, property_name, validation_policy, source) Rules: Reject mutations if entity revoked Logs set/delete Default policy 'default' validation_policy is CHAR(19) ca_core/metadata.py Updates metadata fields Manages defense_p Logs changes ca_core/db_logging.py log_change(cursor, message: str) Inserts into log(entry). Tests tests/test_entity.py tests/test_group.py tests/test_property.py tests/test_metadata.py Tests verify: Creation and enrollment Group membership Revocation immutability CA reference enforcement Property metadata fields defense_p behavior Log entry creation (case-insensitive substring checks) Run via: python3 -m unittest discover Known Gotchas Do NOT name module logging.py (conflicts with stdlib) Schema and code must stay aligned: property.id (NOT entity_id) group_member.member_id entity.ca_reference constraint CHAR(19) pads values with spaces