Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
246 commits
Select commit Hold shift + click to select a range
09c9ca3
feat: add bitemporal people domain kernel
seonghobae Aug 15, 2026
cbd86b5
merge: refresh foundation baseline
seonghobae Aug 15, 2026
03ff43c
feat(postgres): add purpose-bound persistence package
seonghobae Aug 15, 2026
0567175
docs(postgres): describe persistence authority boundary
seonghobae Aug 15, 2026
6c446bd
feat(postgres): define purpose-bound request context
seonghobae Aug 15, 2026
5213b8c
feat(postgres): add stable repository errors
seonghobae Aug 15, 2026
3a5f27b
feat(postgres): add immutable persistence projections
seonghobae Aug 15, 2026
70d3282
feat(postgres): implement transactional people repository
seonghobae Aug 15, 2026
f6a1b77
feat(postgres): publish repository API
seonghobae Aug 15, 2026
a3f23fa
chore(postgres): mark package as typed
seonghobae Aug 15, 2026
0a074fc
feat(postgres): add tenant isolation and audit boundary
seonghobae Aug 15, 2026
2686e34
test(postgres): define purpose and failure contracts
seonghobae Aug 15, 2026
87e11f4
test(postgres): cover invisible cross-tenant identity conflicts
seonghobae Aug 15, 2026
f6d913f
test(postgres): exercise real tenant and audit behavior
seonghobae Aug 15, 2026
79a681b
test(postgres): enforce public docstring coverage
seonghobae Aug 15, 2026
f748b0a
build(postgres): pin test and runtime dependencies
seonghobae Aug 15, 2026
20b2271
ci(postgres): add real PostgreSQL quality gate
seonghobae Aug 15, 2026
6f931e6
docs(postgres): record persistence boundary decision
seonghobae Aug 15, 2026
4269cdf
docs(postgres): document operator and host contract
seonghobae Aug 15, 2026
8d1fb6b
docs(postgres): record unreleased persistence slice
seonghobae Aug 15, 2026
adb86e0
test(postgres): enforce migration naming and tenant policy contract
seonghobae Aug 15, 2026
02eacc6
docs(postgres): add APA 7 persistence references
seonghobae Aug 15, 2026
bfc277d
docs(postgres): trace persistence requirements to evidence
seonghobae Aug 15, 2026
543d7b2
test(postgres): enforce immutable and secret-minimal CI contract
seonghobae Aug 15, 2026
71a5278
test(postgres): enforce reference-only audit evidence
seonghobae Aug 15, 2026
97d79f2
docs(postgres): define PII access and control evidence
seonghobae Aug 15, 2026
ce5700d
feat(api): add people API package
seonghobae Aug 15, 2026
0564a2f
docs(api): describe purpose-bound people API
seonghobae Aug 15, 2026
3913d85
feat(api): define fail-closed authorization boundary
seonghobae Aug 15, 2026
21ce3dd
feat(api): define people repository port
seonghobae Aug 15, 2026
6680965
feat(api): define strict request and response schemas
seonghobae Aug 15, 2026
691a410
feat(api): add RFC 9457 problem responses
seonghobae Aug 15, 2026
0bbbeb9
feat(api): enforce bounded request and security headers
seonghobae Aug 15, 2026
32e057c
feat(api): implement people and candidate HTTP slice
seonghobae Aug 15, 2026
fcfbc5a
feat(api): publish people API factory
seonghobae Aug 15, 2026
47091e2
chore(api): mark people API package as typed
seonghobae Aug 15, 2026
194a7fe
test(api): add deterministic service doubles
seonghobae Aug 15, 2026
86dd734
test(api): cover authentication and purpose guards
seonghobae Aug 15, 2026
28f6aa8
test(api): exercise purpose-bound HTTP workflows
seonghobae Aug 15, 2026
3a4d9ff
test(api): exercise request boundary middleware
seonghobae Aug 15, 2026
30478f2
test(api): cover strict temporal and code schemas
seonghobae Aug 15, 2026
2a0bff2
test(api): cover factory and problem helper boundaries
seonghobae Aug 15, 2026
6deac78
build(api): pin people API test dependencies
seonghobae Aug 15, 2026
695ae84
test(api): enforce public API docstrings
seonghobae Aug 15, 2026
6fdd051
ci(api): add people API quality gate
seonghobae Aug 15, 2026
938da7b
test(api): enforce immutable and secret-minimal workflow
seonghobae Aug 15, 2026
3164c07
test(api): enforce explicit authority and non-leaking source contracts
seonghobae Aug 15, 2026
ec05a39
docs(api): record purpose-bound people API decision
seonghobae Aug 15, 2026
553688e
docs(api): publish people API v1 contract
seonghobae Aug 15, 2026
4fd9cf8
docs(api): add authority and mutation sequences
seonghobae Aug 15, 2026
0b1d52c
docs(api): define people API threat model
seonghobae Aug 15, 2026
e11783d
docs(api): add APA 7 API and identity references
seonghobae Aug 15, 2026
9a0502a
docs(api): trace people API requirements to evidence
seonghobae Aug 15, 2026
e9785a1
docs(api): record unreleased people API slice
seonghobae Aug 15, 2026
5833e6a
test(api): cover defensive context construction failure
seonghobae Aug 15, 2026
10a7c9a
test(api): cover non-body ASGI receive messages
seonghobae Aug 15, 2026
ddfea60
build(postgres): pin package verification dependencies
seonghobae Aug 15, 2026
12c0318
ci(postgres): add package build and installed-wheel smoke
seonghobae Aug 15, 2026
56a2157
test(postgres): enforce package workflow integrity
seonghobae Aug 15, 2026
38d7812
test(api): cover generic HTTP error normalization
seonghobae Aug 15, 2026
10d6aa9
feat(keyverse): add OIDC authorizer package
seonghobae Aug 15, 2026
717bf78
docs(keyverse): define offline verifier boundary
seonghobae Aug 15, 2026
6a93eee
feat(keyverse): define verifier configuration and ports
seonghobae Aug 15, 2026
2997179
feat(keyverse): implement strict offline JWT authorizer
seonghobae Aug 15, 2026
e8229fa
feat(keyverse): publish OIDC authorizer API
seonghobae Aug 15, 2026
6cf3fea
chore(keyverse): mark authorizer package as typed
seonghobae Aug 15, 2026
dd95d54
test(keyverse): add deterministic JOSE fixtures
seonghobae Aug 15, 2026
4875720
test(keyverse): cover strict verifier configuration
seonghobae Aug 15, 2026
52a806d
test(keyverse): verify valid access token workflow
seonghobae Aug 15, 2026
ba3f82b
test(keyverse): cover JOSE header and key-set failures
seonghobae Aug 15, 2026
0a710a0
test(keyverse): cover registered and private claim failures
seonghobae Aug 15, 2026
e06734d
test(keyverse): translate provider and identity mapping failures
seonghobae Aug 15, 2026
ee28b30
test(keyverse): cover strict JOSE helper boundaries
seonghobae Aug 15, 2026
a395abc
test(keyverse): cover configuration helper boundaries
seonghobae Aug 15, 2026
6a654c5
test(keyverse): enforce public authorizer docstrings
seonghobae Aug 15, 2026
d4cc402
test(keyverse): enforce offline and asymmetric verifier contract
seonghobae Aug 15, 2026
8713483
build(keyverse): pin authorization test dependencies
seonghobae Aug 15, 2026
0a2abbd
ci(keyverse): add strict authorization quality gate
seonghobae Aug 15, 2026
b0099f3
test(keyverse): enforce immutable and secret-minimal CI
seonghobae Aug 15, 2026
c5822ea
docs(keyverse): record offline JWT authorizer decision
seonghobae Aug 15, 2026
fe3c762
docs(keyverse): publish strict access-token profile
seonghobae Aug 15, 2026
668dd70
docs(keyverse): define OIDC authorizer threat model
seonghobae Aug 15, 2026
d803e93
docs(keyverse): add APA 7 JOSE and access-token references
seonghobae Aug 15, 2026
26cd479
docs(keyverse): trace strict authorization requirements to evidence
seonghobae Aug 15, 2026
38af059
docs(keyverse): add offline authorization sequences
seonghobae Aug 15, 2026
5a6cb91
docs(keyverse): record unreleased authorization slice
seonghobae Aug 15, 2026
3e73072
build(keyverse): pin package verification tools
seonghobae Aug 15, 2026
c3ed6b8
ci(keyverse): add package build and installed-wheel smoke
seonghobae Aug 15, 2026
fc98b75
test(keyverse): enforce package workflow integrity
seonghobae Aug 15, 2026
c7c7b61
test: separate durable person identity from effective names
seonghobae Aug 16, 2026
99f40a0
fix: separate person anchor from effective name facts
seonghobae Aug 16, 2026
6a842fb
test(postgres): cover documented base psycopg failure
seonghobae Aug 16, 2026
32791a4
fix(postgres): use documented Psycopg base error
seonghobae Aug 16, 2026
d2575c0
fix(api): use Python 3.14-compatible Pydantic lock
seonghobae Aug 16, 2026
23baa6a
fix(auth): use Python 3.14-compatible Pydantic lock
seonghobae Aug 16, 2026
b3dce34
test: require organization and job domain records
seonghobae Aug 16, 2026
b98f307
feat: model bitemporal organization and job records
seonghobae Aug 16, 2026
f095b06
feat: export organization and job domain records
seonghobae Aug 16, 2026
85ffc72
docs: describe organization and job domain coverage
seonghobae Aug 16, 2026
5c3b341
docs: trace organization and job domain records
seonghobae Aug 16, 2026
3d9b469
docs: record organization and job domain slice
seonghobae Aug 16, 2026
32ef213
test: separate organization and job identity from versions
seonghobae Aug 16, 2026
d017128
fix: normalize organization and job version facts
seonghobae Aug 16, 2026
4d38390
fix: export normalized organization and job versions
seonghobae Aug 16, 2026
e47e787
docs: explain normalized organization and job history
seonghobae Aug 16, 2026
7b72ec1
docs: trace durable organization and job anchors
seonghobae Aug 16, 2026
c8180d0
docs: record normalized organization and job history
seonghobae Aug 16, 2026
a8323f4
fix(auth): enforce JWK verification key operations
seonghobae Aug 16, 2026
8ae912a
docs(auth): preserve authorizer API docstring gate
seonghobae Aug 16, 2026
5bd7cf4
merge: update People API persistence dependency
seonghobae Aug 16, 2026
602f634
merge: refresh Keyverse authorization dependency stack
seonghobae Aug 16, 2026
c6a12dd
test(api): reproduce identity-provider outage mapping
seonghobae Aug 16, 2026
e4677f1
fix(api): classify identity-provider outages as retryable
seonghobae Aug 16, 2026
44b0a1b
feat(api): export retryable identity-provider failure
seonghobae Aug 16, 2026
c89e612
test: reproduce unsafe assignment numeric and error behavior
seonghobae Aug 16, 2026
4b133ca
fix: fail closed on unsafe assignment allocations
seonghobae Aug 16, 2026
86405c4
test: align allocation overlap assertion with safe error contract
seonghobae Aug 16, 2026
f1fe180
test: require installed-wheel quality evidence
seonghobae Aug 16, 2026
9d9bfcb
build: pin wheel backend for artifact smoke
seonghobae Aug 16, 2026
9d830e8
build: prove typed wheel installs outside source tree
seonghobae Aug 16, 2026
2ce30f4
test: require explicit person-anchor lifecycle boundary
seonghobae Aug 16, 2026
3eebded
docs: define person-anchor recorded lifecycle ownership
seonghobae Aug 16, 2026
32f0a61
test: reject unsafe purpose and evidence metadata
seonghobae Aug 16, 2026
f9127b2
fix: constrain purpose-bound audit metadata
seonghobae Aug 16, 2026
143f26d
test: reproduce caller-owned system-time defect
seonghobae Aug 16, 2026
9f1644d
fix: make PostgreSQL the system-time authority
seonghobae Aug 16, 2026
a522785
test: prove business time cannot control knowledge time
seonghobae Aug 16, 2026
6698815
test: reproduce client-visible internal trace leakage
seonghobae Aug 16, 2026
deb2bf0
fix: separate client support IDs from internal traces
seonghobae Aug 16, 2026
1bead24
fix: return opaque support references in problem details
seonghobae Aug 16, 2026
46afb20
test: enforce client-safe support-reference boundary
seonghobae Aug 16, 2026
eae76e1
test: keep disconnect responses trace-private
seonghobae Aug 16, 2026
7b28df4
test: require support references without middleware
seonghobae Aug 16, 2026
da3138f
test: ban trace identifiers from client problem schema
seonghobae Aug 16, 2026
3912c7a
test: reproduce purpose-only capability escalation
seonghobae Aug 16, 2026
10a81f1
fix: authorize OAuth scopes independently of HR purpose
seonghobae Aug 16, 2026
e5c30f1
api: export independent scope authorization guard
seonghobae Aug 16, 2026
81e4504
fix: require route scope and remove header provenance authority
seonghobae Aug 16, 2026
5a02aca
test: adapt API doubles to scope and server-time contracts
seonghobae Aug 16, 2026
82f553f
fix: remove caller-owned knowledge time from API port
seonghobae Aug 16, 2026
8615cab
fix: keep system-recorded time off public person commands
seonghobae Aug 16, 2026
e2669fc
test: cover independent scope and purpose grants
seonghobae Aug 16, 2026
d43fe91
fix: generate non-semantic support references
seonghobae Aug 16, 2026
c8069e1
fix: align support references with opaque error contract
seonghobae Aug 16, 2026
d082654
fix: enforce opaque error-reference shape and neutral denial
seonghobae Aug 16, 2026
fb21070
test: require foundation-shaped support identifiers
seonghobae Aug 16, 2026
e5cdad2
test: use opaque support tokens on disconnect responses
seonghobae Aug 16, 2026
f6227f4
test: prove random opaque support-reference shape
seonghobae Aug 16, 2026
a5da8f1
test: remove header-provenance helper assumptions
seonghobae Aug 16, 2026
8371c0a
test: repair defensive-context syntax and scope setup
seonghobae Aug 16, 2026
d23759d
test: adapt identity outage to scope-purpose authorizer
seonghobae Aug 16, 2026
c927926
test: align endpoints with scope, provenance, and server-time policy
seonghobae Aug 16, 2026
3686ec1
test: enforce system-time exclusion at schema boundary
seonghobae Aug 16, 2026
8975604
test: lock scope, provenance, and system-time source contracts
seonghobae Aug 16, 2026
7883a99
docs: align People API contract with repaired authority boundaries
seonghobae Aug 16, 2026
9750525
docs: record two-dimensional API authority and time ownership
seonghobae Aug 16, 2026
7054b9a
docs: update People API threat model for repaired trust boundaries
seonghobae Aug 16, 2026
89f4091
test(postgres): require bitemporal person-name persistence
seonghobae Aug 16, 2026
219d87a
fix(postgres): version person names outside identity anchor
seonghobae Aug 16, 2026
dd85e4e
fix(postgres): align repository with durable person schema
seonghobae Aug 16, 2026
d063620
test(postgres): require exact-head quality checkout
seonghobae Aug 16, 2026
39d891c
test(postgres): require exact-head package checkout
seonghobae Aug 16, 2026
ce10027
fix(ci): test exact PostgreSQL pull request head
seonghobae Aug 16, 2026
b4bc798
fix(ci): package exact PostgreSQL pull request head
seonghobae Aug 16, 2026
0f257b5
test(domain): require exact-head workflow evidence
seonghobae Aug 16, 2026
ab7720f
fix(ci): bind domain quality to exact pull request head
seonghobae Aug 16, 2026
36c6110
fix(postgres): remove unreachable name-return guard
seonghobae Aug 16, 2026
592481f
merge(stack): carry exact-head domain workflow regression
seonghobae Aug 16, 2026
483e1b7
merge(stack): carry exact-head domain workflow fix
seonghobae Aug 16, 2026
d7277c1
merge(stack): synchronize current domain dependency
seonghobae Aug 16, 2026
3d61b0d
fix(stack): preserve current domain parent semantics
seonghobae Aug 16, 2026
cdaf2f1
merge(stack): synchronize current persistence dependency
seonghobae Aug 16, 2026
52a3b94
merge(stack): synchronize current People API dependency
seonghobae Aug 16, 2026
7fc36ef
test(keyverse): require exact-head authorization checkout
seonghobae Aug 16, 2026
5d33db8
test(keyverse): require exact-head package checkout
seonghobae Aug 16, 2026
45edcd7
fix(ci): bind Keyverse quality to exact pull request head
seonghobae Aug 16, 2026
dc8a008
fix(ci): bind Keyverse package to exact pull request head
seonghobae Aug 16, 2026
9f7607d
test(api): require exact-head People API checkout
seonghobae Aug 16, 2026
b330ad2
fix(ci): bind People API quality to exact pull request head
seonghobae Aug 16, 2026
4ac5e18
test: require independent OAuth operation scopes
seonghobae Aug 16, 2026
c7968f1
test: issue scoped access-token fixtures
seonghobae Aug 16, 2026
be3cb50
test: exercise independent scope and purpose grants
seonghobae Aug 16, 2026
02756ce
fix: enforce OAuth operation scope independently
seonghobae Aug 16, 2026
81dba84
test: update hostile claim cases for scope-bound authorizer
seonghobae Aug 16, 2026
f840558
test: bind JOSE failures to required operation scope
seonghobae Aug 16, 2026
89f5881
test: preserve dependency failures under scope-bound authorization
seonghobae Aug 16, 2026
73eb43d
test: cover scope parser security branches
seonghobae Aug 16, 2026
6abb46f
docs: correct OAuth scope standards traceability
seonghobae Aug 16, 2026
2bb08f7
docs: specify independent RFC 9068 operation scopes
seonghobae Aug 16, 2026
63eeb39
docs: bind Keyverse authorization to scope and purpose
seonghobae Aug 16, 2026
adfe53e
docs: show independent scope and purpose authorization
seonghobae Aug 16, 2026
44a1232
docs: trace independent OAuth scope enforcement
seonghobae Aug 16, 2026
a004b86
chore: record independent Keyverse scope enforcement
seonghobae Aug 16, 2026
31aef2b
test: reject stale stack governance wording
seonghobae Aug 16, 2026
a7fa891
fix: reject stripped controls and own identity claim validation
seonghobae Aug 16, 2026
f8460bd
docs: align People API stack with canonical foundation
seonghobae Aug 16, 2026
7c9d59b
docs: align architecture with protected default branch
seonghobae Aug 16, 2026
8cf4178
docs: follow protected default branch truth
seonghobae Aug 16, 2026
c70e591
docs: clarify active People API truth boundary
seonghobae Aug 16, 2026
89d2fb4
test: catch line-wrapped stale protected-main wording
seonghobae Aug 16, 2026
1ac9230
fix: reject controls before config normalization
seonghobae Aug 16, 2026
bf5d2c9
docs: align People API UML truth boundary
seonghobae Aug 16, 2026
82790df
test: keep hostile purpose cases JSON-representable
seonghobae Aug 16, 2026
9bd7301
test: keep JOSE integration cases encoder-realistic
seonghobae Aug 16, 2026
e5d464d
test: bind People API integrity manifest to active stack
seonghobae Aug 16, 2026
4110eee
fix: reject hidden controls across verifier configuration
seonghobae Aug 16, 2026
73eb43b
test: cover hidden controls in verifier config
seonghobae Aug 16, 2026
a9502fa
refactor: simplify compact token validation
seonghobae Aug 16, 2026
2ee3bbf
test: require installed local dependency chain in wheel smoke
seonghobae Aug 16, 2026
c299244
fix: install declared local dependencies in package smoke
seonghobae Aug 16, 2026
78a06c6
test: leave null registered-claim handling to JWT profile
seonghobae Aug 16, 2026
94f5715
test: cover strict JOSE and authorization character branches
seonghobae Aug 16, 2026
d67af62
fix: keep People API dependencies server-owned
cursoragent Aug 16, 2026
00c339c
docs: record People API runtime dependency boundary
cursoragent Aug 16, 2026
16590b0
merge: refresh People API dependency stack
cursoragent Aug 16, 2026
af6d0b2
chore: bind integrity manifest to the People API stack
cursoragent Aug 16, 2026
f4595f1
fix: align People API CI lock with Python 3.14 Pydantic
cursoragent Aug 16, 2026
b7d8584
feat: expose hire-to-employment People API
cursoragent Aug 16, 2026
ccb020a
refactor: rebuild People API on protected contracts
seonghobae Aug 17, 2026
8ad1867
fix: remove unused People API test import
seonghobae Aug 17, 2026
fb356d3
test: require governed worker People read path
seonghobae Aug 17, 2026
a315ee2
feat: add governed worker People read service
seonghobae Aug 17, 2026
b5647c9
feat: export governed worker read contracts
seonghobae Aug 17, 2026
028951b
docs: describe governed People read path
seonghobae Aug 17, 2026
5592c1a
test: harden People principal validation coverage
seonghobae Aug 17, 2026
1181f05
test: cover governed People read fail-closed branches
seonghobae Aug 17, 2026
3492387
test: require exact People API branch coverage
seonghobae Aug 17, 2026
de2ada5
ci: enforce 100% People API branch coverage
seonghobae Aug 17, 2026
a6422cf
test: require tenant-bound PostgreSQL People reads
seonghobae Aug 17, 2026
a4d264a
feat: bind People reads to PostgreSQL tenant RLS
seonghobae Aug 17, 2026
cde0ce7
feat: export PostgreSQL People read adapter
seonghobae Aug 17, 2026
bc6e8a4
test: require People API CI on develop PRs
seonghobae Aug 17, 2026
6026077
fix: dispatch People API quality on develop PRs
seonghobae Aug 17, 2026
3e6ff9b
docs: document tenant-bound People persistence
seonghobae Aug 17, 2026
2169e06
test: require Foundation CI on develop PRs
seonghobae Aug 17, 2026
c42f1b5
fix: dispatch Foundation CI on develop PRs
seonghobae Aug 17, 2026
7d7a53d
fix: refresh Foundation CI manifest
seonghobae Aug 17, 2026
2455dd0
test: define governed People HTTP route contract
seonghobae Aug 17, 2026
debd5a6
test: fix missing-authorization HTTP fixture
seonghobae Aug 17, 2026
b644021
feat: expose governed People ASGI read route
seonghobae Aug 17, 2026
a521631
feat: export governed People ASGI app
seonghobae Aug 17, 2026
eb6f4f0
fix: validate the exact People HTTP route shape
seonghobae Aug 17, 2026
0318c87
test: cover People HTTP fail-closed boundaries
seonghobae Aug 17, 2026
dd43f5a
docs: document governed People HTTP route
seonghobae Aug 17, 2026
6cdb2b7
chore: retrigger Required Noema Review after GitHub 503
cursoragent Aug 17, 2026
5ccec98
chore: retrigger Noema and CodeQL after GitHub 503
cursoragent Aug 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/foundation-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
pull_request:
branches:
- bootstrap
- develop
- main
- feat/foundation-product-baseline
push:
Expand Down
57 changes: 57 additions & 0 deletions .github/workflows/people-api-quality.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: People API Quality

on:
pull_request:
branches:
- bootstrap
- develop
- main
paths:
- "services/people-api/**"
- "packages/keyverse-adapter/**"
- ".github/requirements/foundation-test.txt"
- ".github/workflows/people-api-quality.yml"
workflow_dispatch:

permissions:
contents: read

concurrency:
group: people-api-quality-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
unit:
name: People API contract and 100% coverage
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout exact candidate
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
persist-credentials: false
- name: Prove exact candidate checkout
env:
ORGMETRA_EXPECTED_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
run: test "$(git rev-parse HEAD)" = "$ORGMETRA_EXPECTED_HEAD_SHA"
- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.14"
check-latest: false
- name: Install reviewed test toolchain
run: |
python -m pip install --require-hashes --no-deps --only-binary=:all: -r .github/requirements/foundation-test.txt
python -m pip check
- name: Compile People API boundary
run: python -m compileall -q services/people-api/src packages/keyverse-adapter/src services/people-api/tests
- name: Test governed People contracts with exact statement and branch coverage
env:
PYTHONPATH: services/people-api/src:packages/keyverse-adapter/src
COVERAGE_FILE: /tmp/orgmetra-people-api.coverage
run: python -m pytest -c services/people-api/pyproject.toml services/people-api/tests
- name: Require clean checkout
run: |
git diff --exit-code
test -z "$(git status --porcelain)"
2 changes: 1 addition & 1 deletion manifest.json

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions services/people-api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Orgmetra People API

This directory is the rebuilt customer-facing People API boundary on the current protected Orgmetra contracts. The historical PR implementation is retained in Git history but is not replayed because it carried a legacy tenant schema, mutable audit shape, duplicated domain kernel, and pre-governance candidate-worker link.

The current bounded slice owns request-edge bearer-token parsing and an injected token-authentication protocol. It deliberately does **not** encode HR purpose grants in the authenticated principal. Protected field access is delegated to the integrated Orgmetra `orgmetra_keyverse_adapter` purpose-bound policy contract, which binds active tenant, actor tenant, resource tenant, exact opaque target reference, purpose, operation, operation-specific scope, and requested field set before protected HR values may be returned.

The service exposes a governed hire-to-employment read contract. `read_worker_people_record()` authorizes the exact opaque `person_record` target **before** invoking the injected `PeopleReadPort`, so a denied purpose, scope, or field request never causes protected worker values to be retrieved. The returned `WorkerPeopleRecord` carries canonical candidate-conversion, person, and employment lineage; tenant/person mismatches returned by persistence fail closed; and the customer view serializes only fields explicitly authorized by the policy decision.

`PostgresPeopleReadPort` is the production read-side adapter for that port. Deployment code supplies a DB-API-compatible connection factory (for example, a configured psycopg connection or pool boundary); the adapter then starts a read-only transaction, binds the exact tenant through transaction-local `orgmetra.tenant_record_id`, and issues only parameterized, fully-qualified SQL against Orgmetra-owned canonical tables. It resolves `candidate_worker_conversion_record`, `person_record`, `person_name_record`, `employment_record`, and `employment_record_version` using current recorded-time truth plus the requested business date. It fetches at most two rows and rejects duplicate current lineage instead of silently choosing one. Pooling, credentials, TLS and database-role selection remain deployment concerns rather than being embedded in the service package.

`PeopleAsgiApp` exposes that governed read use case as a dependency-light ASGI route: `GET /v1/tenants/{tenant_record_id}/people/{person_record_id}?effective_on=YYYY-MM-DD&purpose=people_read&fields=...`. It validates the exact route and query shape before authentication, accepts exactly one ASCII Bearer credential, delegates authentication and purpose-bound authorization to injected contracts, and never reads protected worker values after a denied authorization decision. Successful responses contain only authorized fields; all HTTP responses use `Cache-Control: no-store` and `Vary: Authorization`. Authentication, authorization, missing-record, integrity-conflict, and unexpected-backend failures are mapped to stable non-disclosing responses with a useful next action, and bearer tokens are never returned in response text.

The People API quality workflow is part of this contract and must run for pull requests to every supported protected/default integration branch, including `develop`. Its service tests enforce 100% owned statement and branch coverage and include regression coverage for the workflow dispatch boundary and HTTP security/transport behavior.

The remaining customer-path work on this same canonical branch is the accepted-mutation path that persists authoritative HRIS facts and governed audit/outbox evidence atomically. The superseded persistence model must not be restored, and the service must not use direct cross-service application-table SQL.
39 changes: 39 additions & 0 deletions services/people-api/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
[build-system]
requires = ["setuptools==82.0.1"]
build-backend = "setuptools.build_meta"

[project]
name = "orgmetra-people-api"
version = "0.1.0"
description = "Purpose-bound customer API boundary for authoritative Orgmetra HR records."
readme = "README.md"
requires-python = ">=3.11"
license = { text = "Apache-2.0" }
authors = [{ name = "ContextualWisdomLab" }]
dependencies = ["orgmetra-keyverse-adapter==0.1.0"]

[tool.setuptools]
package-dir = {"" = "src"}

[tool.setuptools.packages.find]
where = ["src"]

[tool.setuptools.package-data]
orgmetra_people_api = ["py.typed"]

[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = [
"--cov=orgmetra_people_api",
"--cov-branch",
"--cov-report=term-missing",
"--cov-fail-under=100",
]

[tool.coverage.run]
branch = true
source = ["orgmetra_people_api"]

[tool.coverage.report]
fail_under = 100
show_missing = true
35 changes: 35 additions & 0 deletions services/people-api/src/orgmetra_people_api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""Request-edge and governed read contracts for the Orgmetra People API."""

from orgmetra_people_api.auth import (
AuthenticatedPrincipal,
AuthenticationFailed,
TokenAuthenticator,
extract_bearer_token,
)
from orgmetra_people_api.authorization import authorize_resource_fields
from orgmetra_people_api.http import PeopleAsgiApp
from orgmetra_people_api.people import (
AuthorizedWorkerPeopleView,
PeopleReadPort,
PeopleRecordIntegrityError,
PeopleRecordNotFound,
WorkerPeopleRecord,
read_worker_people_record,
)
from orgmetra_people_api.postgres import PostgresPeopleReadPort

__all__ = [
"AuthenticatedPrincipal",
"AuthenticationFailed",
"AuthorizedWorkerPeopleView",
"PeopleAsgiApp",
"PeopleReadPort",
"PeopleRecordIntegrityError",
"PeopleRecordNotFound",
"PostgresPeopleReadPort",
"TokenAuthenticator",
"WorkerPeopleRecord",
"authorize_resource_fields",
"extract_bearer_token",
"read_worker_people_record",
]
77 changes: 77 additions & 0 deletions services/people-api/src/orgmetra_people_api/auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"""Fail-closed request-edge authentication contracts for the People API.

Authentication proves who the caller is and which operation scopes were issued by
the identity boundary. HR purpose and field authorization are intentionally not
stored on this principal; Orgmetra evaluates those attributes through its
purpose-bound policy contract after the target resource has been resolved.
"""

from __future__ import annotations

from dataclasses import dataclass
import re
from typing import Protocol, runtime_checkable
from uuid import UUID

_MAX_UUID_INT = (1 << 128) - 1
_REFERENCE_PATTERN = re.compile(r"^[a-z][a-z0-9_]*:[A-Za-z0-9][A-Za-z0-9._~-]*$")
_SCOPE_PATTERN = re.compile(r"^orgmetra(?:\.[a-z][a-z0-9_]*){2,}$")


class AuthenticationFailed(RuntimeError):
"""Indicate that bearer authentication evidence is absent or malformed."""


@dataclass(frozen=True, slots=True)
class AuthenticatedPrincipal:
"""Identity attributes that may be trusted only after token authentication.

``tenant_record_id`` binds the authenticated actor to one Orgmetra tenant.
``actor_reference`` is opaque audit correlation rather than a person record
identifier. ``granted_scope_codes`` carries explicit operation capabilities;
it never carries an HR purpose decision.
"""

tenant_record_id: UUID
actor_reference: str
granted_scope_codes: frozenset[str]

def __post_init__(self) -> None:
"""Reject sentinel identities, mutable grants, wildcards, and bad references."""
if not isinstance(self.tenant_record_id, UUID):
raise ValueError("tenant_record_id must be a UUID.")
if self.tenant_record_id.int in (0, _MAX_UUID_INT):
raise ValueError("tenant_record_id must not use a reserved UUID sentinel.")
if not isinstance(self.actor_reference, str) or _REFERENCE_PATTERN.fullmatch(self.actor_reference) is None:
raise ValueError("actor_reference must be a namespaced opaque reference.")
if not isinstance(self.granted_scope_codes, frozenset) or not self.granted_scope_codes:
raise ValueError("granted_scope_codes must be a non-empty frozenset.")
if any(not isinstance(scope, str) or _SCOPE_PATTERN.fullmatch(scope) is None for scope in self.granted_scope_codes):
raise ValueError("granted_scope_codes must contain explicit Orgmetra scopes.")


@runtime_checkable
class TokenAuthenticator(Protocol):
"""Authenticate one bearer token without making an HR authorization decision."""

async def authenticate(self, bearer_token: str) -> AuthenticatedPrincipal:
"""Return authenticated identity/scope attributes or raise a stable error."""


def extract_bearer_token(authorization_header: str | None) -> str:
"""Return one bounded printable bearer token without logging its value.

Splitting only on the first ASCII space keeps C0 separators visible so they
are rejected rather than silently treated as whitespace by ``str.split``.
"""
if authorization_header is None:
raise AuthenticationFailed("bearer authentication is required")
parts = authorization_header.split(" ", 1)
if len(parts) != 2 or parts[0].casefold() != "bearer":
raise AuthenticationFailed("authorization must use the Bearer scheme")
token = parts[1]
if not token or len(token) > 8192:
raise AuthenticationFailed("bearer token length is invalid")
if any(ord(character) < 0x21 or ord(character) > 0x7E for character in token):
raise AuthenticationFailed("bearer token contains invalid characters")
return token
47 changes: 47 additions & 0 deletions services/people-api/src/orgmetra_people_api/authorization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""Delegate People API field access to Orgmetra's integrated policy evaluator."""

from __future__ import annotations

from uuid import UUID

from orgmetra_keyverse_adapter import (
AuthorizationDecision,
PurposeBoundAccessPolicy,
PurposeBoundAccessRequest,
require_purpose_bound_access,
)

from orgmetra_people_api.auth import AuthenticatedPrincipal


def authorize_resource_fields(
*,
principal: AuthenticatedPrincipal,
tenant_record_id: UUID,
resource_tenant_record_id: UUID,
resource_reference: str,
purpose_code: str,
operation_code: str,
resource_kind: str,
requested_fields: frozenset[str],
policy: PurposeBoundAccessPolicy,
) -> AuthorizationDecision:
"""Authorize one exact HR resource without duplicating Keyverse policy logic.

The People API contributes only request-edge identity/scope attributes and the
resolved target. The integrated Orgmetra adapter remains the single owner of
tenant/resource/purpose/operation/scope/field evaluation and denial evidence.
"""
request = PurposeBoundAccessRequest(
tenant_record_id=tenant_record_id,
actor_tenant_record_id=principal.tenant_record_id,
resource_tenant_record_id=resource_tenant_record_id,
actor_reference=principal.actor_reference,
resource_reference=resource_reference,
purpose_code=purpose_code,
operation_code=operation_code,
resource_kind=resource_kind,
requested_fields=requested_fields,
granted_scope_codes=principal.granted_scope_codes,
)
return require_purpose_bound_access(request=request, policy=policy)
Loading
Loading