pki_ca/PROJECT_CONTEXT.md

4.4 KiB

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