pki_ca/PROJECT_CONTEXT.md

329 lines
4.4 KiB
Markdown

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