generated from coulomb/repo-seed
Add small SaaS profile proof
This commit is contained in:
12
README.md
12
README.md
@@ -23,6 +23,9 @@ PYTHONPATH=src python3 -m info_tech_canon validate
|
||||
PYTHONPATH=src python3 -m info_tech_canon graph
|
||||
PYTHONPATH=src python3 -m info_tech_canon index
|
||||
PYTHONPATH=src python3 -m info_tech_canon views
|
||||
PYTHONPATH=src python3 -m info_tech_canon profile inspect small-saas
|
||||
PYTHONPATH=src python3 -m info_tech_canon profile validate small-saas
|
||||
PYTHONPATH=src python3 -m info_tech_canon profile graph small-saas
|
||||
PYTHONPATH=src python3 -m info_tech_canon api --host 127.0.0.1 --port 8765
|
||||
```
|
||||
|
||||
@@ -43,6 +46,8 @@ After package installation, the same commands are available through the
|
||||
- `GET /views`
|
||||
- `GET /views/{name}`
|
||||
- `GET /profiles/{profile}/inspect`
|
||||
- `GET /profiles/{profile}/validate`
|
||||
- `GET /profiles/{profile}/graph`
|
||||
|
||||
## Maintenance
|
||||
|
||||
@@ -52,3 +57,10 @@ make index
|
||||
make tree
|
||||
make agent-briefs
|
||||
```
|
||||
|
||||
## First Profile Proof
|
||||
|
||||
The first executable profile proof is `small-saas`. It lives under
|
||||
`infospace/profiles/small-saas/` and includes connected example artifacts for a
|
||||
tenant-aware SaaS service: service, system, tenants, user, team, dataset,
|
||||
deployment, task, policy, control, evidence, and incident.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
This brief summarizes the current canon service surface for agents.
|
||||
|
||||
- Infospace slug: `canon`
|
||||
- Artifact count: 15
|
||||
- Artifact count: 29
|
||||
- Primary confidence command: `make validate`
|
||||
- Refresh generated indexes and views with: `make index`
|
||||
|
||||
|
||||
@@ -224,3 +224,252 @@ artifacts:
|
||||
target: model/task
|
||||
- type: imports
|
||||
target: standard/tagging
|
||||
- id: profile/small-saas
|
||||
path: profiles/small-saas/profile.yaml
|
||||
kind: profile
|
||||
title: Small SaaS System Profile
|
||||
provenance:
|
||||
source_path: infospace/profiles/small-saas/profile.yaml
|
||||
profile: small-saas
|
||||
placement_workplan: ITC-WP-0004
|
||||
relationships:
|
||||
- type: conforms_to
|
||||
target: kernel/itc-core
|
||||
- type: requires
|
||||
target: model/landscape
|
||||
- type: requires
|
||||
target: model/organization
|
||||
- type: requires
|
||||
target: model/governance
|
||||
- type: requires
|
||||
target: model/access-control
|
||||
- type: requires
|
||||
target: model/security
|
||||
- type: requires
|
||||
target: model/data
|
||||
- type: requires
|
||||
target: model/devsecops
|
||||
- type: requires
|
||||
target: model/network
|
||||
- type: requires
|
||||
target: model/observability
|
||||
- type: requires
|
||||
target: model/task
|
||||
- type: requires
|
||||
target: standard/tagging
|
||||
- type: requires
|
||||
target: standard/caring
|
||||
- id: small-saas/service/billing-portal
|
||||
path: profiles/small-saas/artifacts/service.billing-portal.yaml
|
||||
kind: profile-artifact
|
||||
title: Billing Portal Service
|
||||
provenance:
|
||||
profile: small-saas
|
||||
placement_workplan: ITC-WP-0004
|
||||
relationships:
|
||||
- type: instantiates
|
||||
target: profile/small-saas
|
||||
- type: uses
|
||||
target: model/landscape
|
||||
- type: part_of
|
||||
target: small-saas/system/billing-system
|
||||
- type: owned_by
|
||||
target: small-saas/team/platform
|
||||
- id: small-saas/system/billing-system
|
||||
path: profiles/small-saas/artifacts/system.billing-system.yaml
|
||||
kind: profile-artifact
|
||||
title: Small SaaS Billing System
|
||||
provenance:
|
||||
profile: small-saas
|
||||
placement_workplan: ITC-WP-0004
|
||||
relationships:
|
||||
- type: instantiates
|
||||
target: profile/small-saas
|
||||
- type: uses
|
||||
target: model/landscape
|
||||
- type: serves
|
||||
target: small-saas/tenant/acme
|
||||
- type: serves
|
||||
target: small-saas/tenant/globex
|
||||
- id: small-saas/tenant/acme
|
||||
path: profiles/small-saas/artifacts/tenant.acme.yaml
|
||||
kind: profile-artifact
|
||||
title: Acme Tenant
|
||||
provenance:
|
||||
profile: small-saas
|
||||
placement_workplan: ITC-WP-0004
|
||||
relationships:
|
||||
- type: instantiates
|
||||
target: profile/small-saas
|
||||
- type: uses
|
||||
target: model/organization
|
||||
- type: represented_by
|
||||
target: small-saas/user/ada-admin
|
||||
- type: isolated_by
|
||||
target: small-saas/control/namespace-per-tenant
|
||||
- id: small-saas/tenant/globex
|
||||
path: profiles/small-saas/artifacts/tenant.globex.yaml
|
||||
kind: profile-artifact
|
||||
title: Globex Tenant
|
||||
provenance:
|
||||
profile: small-saas
|
||||
placement_workplan: ITC-WP-0004
|
||||
relationships:
|
||||
- type: instantiates
|
||||
target: profile/small-saas
|
||||
- type: uses
|
||||
target: model/organization
|
||||
- type: isolated_by
|
||||
target: small-saas/control/namespace-per-tenant
|
||||
- id: small-saas/user/ada-admin
|
||||
path: profiles/small-saas/artifacts/user.ada-admin.yaml
|
||||
kind: profile-artifact
|
||||
title: Ada Admin
|
||||
provenance:
|
||||
profile: small-saas
|
||||
placement_workplan: ITC-WP-0004
|
||||
relationships:
|
||||
- type: instantiates
|
||||
target: profile/small-saas
|
||||
- type: uses
|
||||
target: model/organization
|
||||
- type: uses
|
||||
target: model/access-control
|
||||
- type: member_of
|
||||
target: small-saas/team/platform
|
||||
- type: has_access_under
|
||||
target: small-saas/policy/tenant-isolation
|
||||
- type: access_evidenced_by
|
||||
target: small-saas/evidence/access-review-2026-05
|
||||
- id: small-saas/team/platform
|
||||
path: profiles/small-saas/artifacts/team.platform.yaml
|
||||
kind: profile-artifact
|
||||
title: Platform Team
|
||||
provenance:
|
||||
profile: small-saas
|
||||
placement_workplan: ITC-WP-0004
|
||||
relationships:
|
||||
- type: instantiates
|
||||
target: profile/small-saas
|
||||
- type: uses
|
||||
target: model/organization
|
||||
- id: small-saas/dataset/subscription-ledger
|
||||
path: profiles/small-saas/artifacts/dataset.subscription-ledger.yaml
|
||||
kind: profile-artifact
|
||||
title: Subscription Ledger Dataset
|
||||
provenance:
|
||||
profile: small-saas
|
||||
placement_workplan: ITC-WP-0004
|
||||
relationships:
|
||||
- type: instantiates
|
||||
target: profile/small-saas
|
||||
- type: uses
|
||||
target: model/data
|
||||
- type: owned_by
|
||||
target: small-saas/service/billing-portal
|
||||
- type: partitioned_for
|
||||
target: small-saas/tenant/acme
|
||||
- type: partitioned_for
|
||||
target: small-saas/tenant/globex
|
||||
- type: governed_by
|
||||
target: small-saas/policy/tenant-isolation
|
||||
- id: small-saas/deployment/production
|
||||
path: profiles/small-saas/artifacts/deployment.production.yaml
|
||||
kind: profile-artifact
|
||||
title: Production Deployment
|
||||
provenance:
|
||||
profile: small-saas
|
||||
placement_workplan: ITC-WP-0004
|
||||
relationships:
|
||||
- type: instantiates
|
||||
target: profile/small-saas
|
||||
- type: uses
|
||||
target: model/devsecops
|
||||
- type: uses
|
||||
target: model/network
|
||||
- type: deploys
|
||||
target: small-saas/service/billing-portal
|
||||
- type: separates
|
||||
target: small-saas/tenant/acme
|
||||
- type: separates
|
||||
target: small-saas/tenant/globex
|
||||
- type: implements
|
||||
target: small-saas/control/namespace-per-tenant
|
||||
- id: small-saas/task/onboard-tenant
|
||||
path: profiles/small-saas/artifacts/task.onboard-tenant.yaml
|
||||
kind: profile-artifact
|
||||
title: Onboard Tenant
|
||||
provenance:
|
||||
profile: small-saas
|
||||
placement_workplan: ITC-WP-0004
|
||||
relationships:
|
||||
- type: instantiates
|
||||
target: profile/small-saas
|
||||
- type: uses
|
||||
target: model/task
|
||||
- type: owned_by
|
||||
target: small-saas/team/platform
|
||||
- type: changes
|
||||
target: small-saas/tenant/acme
|
||||
- type: governed_by
|
||||
target: small-saas/policy/tenant-isolation
|
||||
- id: small-saas/policy/tenant-isolation
|
||||
path: profiles/small-saas/artifacts/policy.tenant-isolation.yaml
|
||||
kind: profile-artifact
|
||||
title: Tenant Isolation Policy
|
||||
provenance:
|
||||
profile: small-saas
|
||||
placement_workplan: ITC-WP-0004
|
||||
relationships:
|
||||
- type: instantiates
|
||||
target: profile/small-saas
|
||||
- type: uses
|
||||
target: model/governance
|
||||
- type: requires
|
||||
target: small-saas/control/namespace-per-tenant
|
||||
- type: evidenced_by
|
||||
target: small-saas/evidence/access-review-2026-05
|
||||
- id: small-saas/control/namespace-per-tenant
|
||||
path: profiles/small-saas/artifacts/control.namespace-per-tenant.yaml
|
||||
kind: profile-artifact
|
||||
title: Namespace Per Tenant Control
|
||||
provenance:
|
||||
profile: small-saas
|
||||
placement_workplan: ITC-WP-0004
|
||||
relationships:
|
||||
- type: instantiates
|
||||
target: profile/small-saas
|
||||
- type: uses
|
||||
target: model/security
|
||||
- type: uses
|
||||
target: standard/caring
|
||||
- type: evidenced_by
|
||||
target: small-saas/evidence/access-review-2026-05
|
||||
- id: small-saas/evidence/access-review-2026-05
|
||||
path: profiles/small-saas/artifacts/evidence.access-review-2026-05.yaml
|
||||
kind: profile-artifact
|
||||
title: Access Review 2026-05
|
||||
provenance:
|
||||
profile: small-saas
|
||||
placement_workplan: ITC-WP-0004
|
||||
relationships:
|
||||
- type: instantiates
|
||||
target: profile/small-saas
|
||||
- type: uses
|
||||
target: model/observability
|
||||
- id: small-saas/incident/cross-tenant-access-attempt
|
||||
path: profiles/small-saas/artifacts/incident.cross-tenant-access-attempt.yaml
|
||||
kind: profile-artifact
|
||||
title: Cross-Tenant Access Attempt
|
||||
provenance:
|
||||
profile: small-saas
|
||||
placement_workplan: ITC-WP-0004
|
||||
relationships:
|
||||
- type: instantiates
|
||||
target: profile/small-saas
|
||||
- type: uses
|
||||
target: model/security
|
||||
- type: constrained_by
|
||||
target: small-saas/control/namespace-per-tenant
|
||||
- type: evidenced_by
|
||||
target: small-saas/evidence/access-review-2026-05
|
||||
|
||||
14
infospace/examples/small-saas/README.md
Normal file
14
infospace/examples/small-saas/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Small SaaS Example
|
||||
|
||||
This example is the first executable profile proof for InfoTechCanon. It
|
||||
models a compact tenant-aware SaaS service with ownership, tenants, users,
|
||||
access grants, data partitioning, deployment, governance policy, evidence, and
|
||||
incident handling.
|
||||
|
||||
Useful commands:
|
||||
|
||||
```bash
|
||||
PYTHONPATH=src python3 -m info_tech_canon profile inspect small-saas
|
||||
PYTHONPATH=src python3 -m info_tech_canon profile validate small-saas
|
||||
PYTHONPATH=src python3 -m info_tech_canon profile graph small-saas
|
||||
```
|
||||
29
infospace/examples/small-saas/demo-commands.yaml
Normal file
29
infospace/examples/small-saas/demo-commands.yaml
Normal file
@@ -0,0 +1,29 @@
|
||||
profile: small-saas
|
||||
commands:
|
||||
inspect:
|
||||
argv:
|
||||
- PYTHONPATH=src
|
||||
- python3
|
||||
- -m
|
||||
- info_tech_canon
|
||||
- profile
|
||||
- inspect
|
||||
- small-saas
|
||||
validate:
|
||||
argv:
|
||||
- PYTHONPATH=src
|
||||
- python3
|
||||
- -m
|
||||
- info_tech_canon
|
||||
- profile
|
||||
- validate
|
||||
- small-saas
|
||||
graph:
|
||||
argv:
|
||||
- PYTHONPATH=src
|
||||
- python3
|
||||
- -m
|
||||
- info_tech_canon
|
||||
- profile
|
||||
- graph
|
||||
- small-saas
|
||||
@@ -1,5 +1,5 @@
|
||||
root: infospace
|
||||
file_count: 50
|
||||
file_count: 67
|
||||
files:
|
||||
- path: README.md
|
||||
directory: .
|
||||
@@ -19,6 +19,12 @@ files:
|
||||
- path: examples/README.md
|
||||
directory: examples
|
||||
name: README.md
|
||||
- path: examples/small-saas/README.md
|
||||
directory: examples/small-saas
|
||||
name: README.md
|
||||
- path: examples/small-saas/demo-commands.yaml
|
||||
directory: examples/small-saas
|
||||
name: demo-commands.yaml
|
||||
- path: indexes/README.md
|
||||
directory: indexes
|
||||
name: README.md
|
||||
@@ -82,9 +88,54 @@ files:
|
||||
- path: profiles/README.md
|
||||
directory: profiles
|
||||
name: README.md
|
||||
- path: profiles/small-saas/artifacts/control.namespace-per-tenant.yaml
|
||||
directory: profiles/small-saas/artifacts
|
||||
name: control.namespace-per-tenant.yaml
|
||||
- path: profiles/small-saas/artifacts/dataset.subscription-ledger.yaml
|
||||
directory: profiles/small-saas/artifacts
|
||||
name: dataset.subscription-ledger.yaml
|
||||
- path: profiles/small-saas/artifacts/deployment.production.yaml
|
||||
directory: profiles/small-saas/artifacts
|
||||
name: deployment.production.yaml
|
||||
- path: profiles/small-saas/artifacts/evidence.access-review-2026-05.yaml
|
||||
directory: profiles/small-saas/artifacts
|
||||
name: evidence.access-review-2026-05.yaml
|
||||
- path: profiles/small-saas/artifacts/incident.cross-tenant-access-attempt.yaml
|
||||
directory: profiles/small-saas/artifacts
|
||||
name: incident.cross-tenant-access-attempt.yaml
|
||||
- path: profiles/small-saas/artifacts/policy.tenant-isolation.yaml
|
||||
directory: profiles/small-saas/artifacts
|
||||
name: policy.tenant-isolation.yaml
|
||||
- path: profiles/small-saas/artifacts/service.billing-portal.yaml
|
||||
directory: profiles/small-saas/artifacts
|
||||
name: service.billing-portal.yaml
|
||||
- path: profiles/small-saas/artifacts/system.billing-system.yaml
|
||||
directory: profiles/small-saas/artifacts
|
||||
name: system.billing-system.yaml
|
||||
- path: profiles/small-saas/artifacts/task.onboard-tenant.yaml
|
||||
directory: profiles/small-saas/artifacts
|
||||
name: task.onboard-tenant.yaml
|
||||
- path: profiles/small-saas/artifacts/team.platform.yaml
|
||||
directory: profiles/small-saas/artifacts
|
||||
name: team.platform.yaml
|
||||
- path: profiles/small-saas/artifacts/tenant.acme.yaml
|
||||
directory: profiles/small-saas/artifacts
|
||||
name: tenant.acme.yaml
|
||||
- path: profiles/small-saas/artifacts/tenant.globex.yaml
|
||||
directory: profiles/small-saas/artifacts
|
||||
name: tenant.globex.yaml
|
||||
- path: profiles/small-saas/artifacts/user.ada-admin.yaml
|
||||
directory: profiles/small-saas/artifacts
|
||||
name: user.ada-admin.yaml
|
||||
- path: profiles/small-saas/profile.yaml
|
||||
directory: profiles/small-saas
|
||||
name: profile.yaml
|
||||
- path: reports/scaffold-placement.md
|
||||
directory: reports
|
||||
name: scaffold-placement.md
|
||||
- path: reports/small-saas-profile-proof.md
|
||||
directory: reports
|
||||
name: small-saas-profile-proof.md
|
||||
- path: schemas/README.md
|
||||
directory: schemas
|
||||
name: README.md
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
concept_count: 30
|
||||
concept_count: 44
|
||||
concepts:
|
||||
- concept: InfoTechCanon Core
|
||||
owner: kernel/itc-core
|
||||
@@ -52,6 +52,62 @@ concepts:
|
||||
owner: model/task
|
||||
path: models/task/InfoTechCanonTaskModel.md
|
||||
source: artifact_title
|
||||
- concept: Small SaaS System Profile
|
||||
owner: profile/small-saas
|
||||
path: profiles/small-saas/profile.yaml
|
||||
source: artifact_title
|
||||
- concept: Namespace Per Tenant Control
|
||||
owner: small-saas/control/namespace-per-tenant
|
||||
path: profiles/small-saas/artifacts/control.namespace-per-tenant.yaml
|
||||
source: artifact_title
|
||||
- concept: Subscription Ledger Dataset
|
||||
owner: small-saas/dataset/subscription-ledger
|
||||
path: profiles/small-saas/artifacts/dataset.subscription-ledger.yaml
|
||||
source: artifact_title
|
||||
- concept: Production Deployment
|
||||
owner: small-saas/deployment/production
|
||||
path: profiles/small-saas/artifacts/deployment.production.yaml
|
||||
source: artifact_title
|
||||
- concept: Access Review 2026-05
|
||||
owner: small-saas/evidence/access-review-2026-05
|
||||
path: profiles/small-saas/artifacts/evidence.access-review-2026-05.yaml
|
||||
source: artifact_title
|
||||
- concept: Cross-Tenant Access Attempt
|
||||
owner: small-saas/incident/cross-tenant-access-attempt
|
||||
path: profiles/small-saas/artifacts/incident.cross-tenant-access-attempt.yaml
|
||||
source: artifact_title
|
||||
- concept: Tenant Isolation Policy
|
||||
owner: small-saas/policy/tenant-isolation
|
||||
path: profiles/small-saas/artifacts/policy.tenant-isolation.yaml
|
||||
source: artifact_title
|
||||
- concept: Billing Portal Service
|
||||
owner: small-saas/service/billing-portal
|
||||
path: profiles/small-saas/artifacts/service.billing-portal.yaml
|
||||
source: artifact_title
|
||||
- concept: Small SaaS Billing System
|
||||
owner: small-saas/system/billing-system
|
||||
path: profiles/small-saas/artifacts/system.billing-system.yaml
|
||||
source: artifact_title
|
||||
- concept: Onboard Tenant
|
||||
owner: small-saas/task/onboard-tenant
|
||||
path: profiles/small-saas/artifacts/task.onboard-tenant.yaml
|
||||
source: artifact_title
|
||||
- concept: Platform Team
|
||||
owner: small-saas/team/platform
|
||||
path: profiles/small-saas/artifacts/team.platform.yaml
|
||||
source: artifact_title
|
||||
- concept: Acme Tenant
|
||||
owner: small-saas/tenant/acme
|
||||
path: profiles/small-saas/artifacts/tenant.acme.yaml
|
||||
source: artifact_title
|
||||
- concept: Globex Tenant
|
||||
owner: small-saas/tenant/globex
|
||||
path: profiles/small-saas/artifacts/tenant.globex.yaml
|
||||
source: artifact_title
|
||||
- concept: Ada Admin
|
||||
owner: small-saas/user/ada-admin
|
||||
path: profiles/small-saas/artifacts/user.ada-admin.yaml
|
||||
source: artifact_title
|
||||
- concept: InfoTechCanon CARING Access Governance Standard
|
||||
owner: standard/caring
|
||||
path: standards/caring/InfoTechCanonCaringAccessGovernanceStandard.md
|
||||
|
||||
@@ -12,6 +12,20 @@ artifacts:
|
||||
- model/organization
|
||||
- model/security
|
||||
- model/task
|
||||
- profile/small-saas
|
||||
- small-saas/control/namespace-per-tenant
|
||||
- small-saas/dataset/subscription-ledger
|
||||
- small-saas/deployment/production
|
||||
- small-saas/evidence/access-review-2026-05
|
||||
- small-saas/incident/cross-tenant-access-attempt
|
||||
- small-saas/policy/tenant-isolation
|
||||
- small-saas/service/billing-portal
|
||||
- small-saas/system/billing-system
|
||||
- small-saas/task/onboard-tenant
|
||||
- small-saas/team/platform
|
||||
- small-saas/tenant/acme
|
||||
- small-saas/tenant/globex
|
||||
- small-saas/user/ada-admin
|
||||
- standard/caring
|
||||
- standard/tagging
|
||||
rows:
|
||||
@@ -105,6 +119,170 @@ rows:
|
||||
targets:
|
||||
kernel/itc-core:
|
||||
- conforms_to
|
||||
- artifact: profile/small-saas
|
||||
targets:
|
||||
kernel/itc-core:
|
||||
- conforms_to
|
||||
model/access-control:
|
||||
- requires
|
||||
model/data:
|
||||
- requires
|
||||
model/devsecops:
|
||||
- requires
|
||||
model/governance:
|
||||
- requires
|
||||
model/landscape:
|
||||
- requires
|
||||
model/network:
|
||||
- requires
|
||||
model/observability:
|
||||
- requires
|
||||
model/organization:
|
||||
- requires
|
||||
model/security:
|
||||
- requires
|
||||
model/task:
|
||||
- requires
|
||||
standard/caring:
|
||||
- requires
|
||||
standard/tagging:
|
||||
- requires
|
||||
- artifact: small-saas/control/namespace-per-tenant
|
||||
targets:
|
||||
model/security:
|
||||
- uses
|
||||
profile/small-saas:
|
||||
- instantiates
|
||||
small-saas/evidence/access-review-2026-05:
|
||||
- evidenced_by
|
||||
standard/caring:
|
||||
- uses
|
||||
- artifact: small-saas/dataset/subscription-ledger
|
||||
targets:
|
||||
model/data:
|
||||
- uses
|
||||
profile/small-saas:
|
||||
- instantiates
|
||||
small-saas/policy/tenant-isolation:
|
||||
- governed_by
|
||||
small-saas/service/billing-portal:
|
||||
- owned_by
|
||||
small-saas/tenant/acme:
|
||||
- partitioned_for
|
||||
small-saas/tenant/globex:
|
||||
- partitioned_for
|
||||
- artifact: small-saas/deployment/production
|
||||
targets:
|
||||
model/devsecops:
|
||||
- uses
|
||||
model/network:
|
||||
- uses
|
||||
profile/small-saas:
|
||||
- instantiates
|
||||
small-saas/control/namespace-per-tenant:
|
||||
- implements
|
||||
small-saas/service/billing-portal:
|
||||
- deploys
|
||||
small-saas/tenant/acme:
|
||||
- separates
|
||||
small-saas/tenant/globex:
|
||||
- separates
|
||||
- artifact: small-saas/evidence/access-review-2026-05
|
||||
targets:
|
||||
model/observability:
|
||||
- uses
|
||||
profile/small-saas:
|
||||
- instantiates
|
||||
- artifact: small-saas/incident/cross-tenant-access-attempt
|
||||
targets:
|
||||
model/security:
|
||||
- uses
|
||||
profile/small-saas:
|
||||
- instantiates
|
||||
small-saas/control/namespace-per-tenant:
|
||||
- constrained_by
|
||||
small-saas/evidence/access-review-2026-05:
|
||||
- evidenced_by
|
||||
- artifact: small-saas/policy/tenant-isolation
|
||||
targets:
|
||||
model/governance:
|
||||
- uses
|
||||
profile/small-saas:
|
||||
- instantiates
|
||||
small-saas/control/namespace-per-tenant:
|
||||
- requires
|
||||
small-saas/evidence/access-review-2026-05:
|
||||
- evidenced_by
|
||||
- artifact: small-saas/service/billing-portal
|
||||
targets:
|
||||
model/landscape:
|
||||
- uses
|
||||
profile/small-saas:
|
||||
- instantiates
|
||||
small-saas/system/billing-system:
|
||||
- part_of
|
||||
small-saas/team/platform:
|
||||
- owned_by
|
||||
- artifact: small-saas/system/billing-system
|
||||
targets:
|
||||
model/landscape:
|
||||
- uses
|
||||
profile/small-saas:
|
||||
- instantiates
|
||||
small-saas/tenant/acme:
|
||||
- serves
|
||||
small-saas/tenant/globex:
|
||||
- serves
|
||||
- artifact: small-saas/task/onboard-tenant
|
||||
targets:
|
||||
model/task:
|
||||
- uses
|
||||
profile/small-saas:
|
||||
- instantiates
|
||||
small-saas/policy/tenant-isolation:
|
||||
- governed_by
|
||||
small-saas/team/platform:
|
||||
- owned_by
|
||||
small-saas/tenant/acme:
|
||||
- changes
|
||||
- artifact: small-saas/team/platform
|
||||
targets:
|
||||
model/organization:
|
||||
- uses
|
||||
profile/small-saas:
|
||||
- instantiates
|
||||
- artifact: small-saas/tenant/acme
|
||||
targets:
|
||||
model/organization:
|
||||
- uses
|
||||
profile/small-saas:
|
||||
- instantiates
|
||||
small-saas/control/namespace-per-tenant:
|
||||
- isolated_by
|
||||
small-saas/user/ada-admin:
|
||||
- represented_by
|
||||
- artifact: small-saas/tenant/globex
|
||||
targets:
|
||||
model/organization:
|
||||
- uses
|
||||
profile/small-saas:
|
||||
- instantiates
|
||||
small-saas/control/namespace-per-tenant:
|
||||
- isolated_by
|
||||
- artifact: small-saas/user/ada-admin
|
||||
targets:
|
||||
model/access-control:
|
||||
- uses
|
||||
model/organization:
|
||||
- uses
|
||||
profile/small-saas:
|
||||
- instantiates
|
||||
small-saas/evidence/access-review-2026-05:
|
||||
- access_evidenced_by
|
||||
small-saas/policy/tenant-isolation:
|
||||
- has_access_under
|
||||
small-saas/team/platform:
|
||||
- member_of
|
||||
- artifact: standard/caring
|
||||
targets:
|
||||
kernel/itc-core:
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
id: small-saas/control/namespace-per-tenant
|
||||
kind: control
|
||||
title: Namespace Per Tenant Control
|
||||
profile: small-saas
|
||||
policy_id: small-saas/policy/tenant-isolation
|
||||
claim: Every production tenant has a distinct runtime namespace and data partition.
|
||||
control_type: preventive
|
||||
evidence_ids:
|
||||
- small-saas/evidence/access-review-2026-05
|
||||
relationships:
|
||||
- type: satisfies
|
||||
target: small-saas/policy/tenant-isolation
|
||||
- type: evidenced_by
|
||||
target: small-saas/evidence/access-review-2026-05
|
||||
@@ -0,0 +1,21 @@
|
||||
id: small-saas/dataset/subscription-ledger
|
||||
kind: dataset
|
||||
title: Subscription Ledger Dataset
|
||||
profile: small-saas
|
||||
owner_service: small-saas/service/billing-portal
|
||||
classification: customer-confidential
|
||||
tenant_scope: per-tenant
|
||||
tenant_ids:
|
||||
- small-saas/tenant/acme
|
||||
- small-saas/tenant/globex
|
||||
evidence_ids:
|
||||
- small-saas/evidence/access-review-2026-05
|
||||
relationships:
|
||||
- type: owned_by
|
||||
target: small-saas/service/billing-portal
|
||||
- type: partitioned_for
|
||||
target: small-saas/tenant/acme
|
||||
- type: partitioned_for
|
||||
target: small-saas/tenant/globex
|
||||
- type: governed_by
|
||||
target: small-saas/policy/tenant-isolation
|
||||
@@ -0,0 +1,22 @@
|
||||
id: small-saas/deployment/production
|
||||
kind: deployment
|
||||
title: Production Deployment
|
||||
profile: small-saas
|
||||
service_id: small-saas/service/billing-portal
|
||||
environment: production
|
||||
namespace_strategy: namespace-per-tenant
|
||||
tenant_namespaces:
|
||||
small-saas/tenant/acme: tenant-acme
|
||||
small-saas/tenant/globex: tenant-globex
|
||||
network_exposure: public-ingress-authenticated
|
||||
evidence_ids:
|
||||
- small-saas/evidence/access-review-2026-05
|
||||
relationships:
|
||||
- type: deploys
|
||||
target: small-saas/service/billing-portal
|
||||
- type: separates
|
||||
target: small-saas/tenant/acme
|
||||
- type: separates
|
||||
target: small-saas/tenant/globex
|
||||
- type: implements
|
||||
target: small-saas/control/namespace-per-tenant
|
||||
@@ -0,0 +1,18 @@
|
||||
id: small-saas/evidence/access-review-2026-05
|
||||
kind: evidence
|
||||
title: Access Review 2026-05
|
||||
profile: small-saas
|
||||
evidence_type: review-record
|
||||
date: "2026-05-23"
|
||||
supports:
|
||||
- small-saas/service/billing-portal
|
||||
- small-saas/policy/tenant-isolation
|
||||
- small-saas/control/namespace-per-tenant
|
||||
- small-saas/incident/cross-tenant-access-attempt
|
||||
relationships:
|
||||
- type: supports
|
||||
target: small-saas/policy/tenant-isolation
|
||||
- type: supports
|
||||
target: small-saas/control/namespace-per-tenant
|
||||
- type: supports
|
||||
target: small-saas/incident/cross-tenant-access-attempt
|
||||
@@ -0,0 +1,15 @@
|
||||
id: small-saas/incident/cross-tenant-access-attempt
|
||||
kind: incident
|
||||
title: Cross-Tenant Access Attempt
|
||||
profile: small-saas
|
||||
status: resolved
|
||||
tenant_id: small-saas/tenant/acme
|
||||
control_ids:
|
||||
- small-saas/control/namespace-per-tenant
|
||||
evidence_ids:
|
||||
- small-saas/evidence/access-review-2026-05
|
||||
relationships:
|
||||
- type: constrained_by
|
||||
target: small-saas/control/namespace-per-tenant
|
||||
- type: evidenced_by
|
||||
target: small-saas/evidence/access-review-2026-05
|
||||
@@ -0,0 +1,15 @@
|
||||
id: small-saas/policy/tenant-isolation
|
||||
kind: policy
|
||||
title: Tenant Isolation Policy
|
||||
profile: small-saas
|
||||
scope: service-and-data-plane
|
||||
statement: Tenant requests, namespaces, access grants, and data partitions must not cross tenant boundaries.
|
||||
control_ids:
|
||||
- small-saas/control/namespace-per-tenant
|
||||
evidence_ids:
|
||||
- small-saas/evidence/access-review-2026-05
|
||||
relationships:
|
||||
- type: requires
|
||||
target: small-saas/control/namespace-per-tenant
|
||||
- type: evidenced_by
|
||||
target: small-saas/evidence/access-review-2026-05
|
||||
@@ -0,0 +1,28 @@
|
||||
id: small-saas/service/billing-portal
|
||||
kind: service
|
||||
title: Billing Portal Service
|
||||
profile: small-saas
|
||||
system_id: small-saas/system/billing-system
|
||||
owner_team: small-saas/team/platform
|
||||
runtime_deployment: small-saas/deployment/production
|
||||
datasets:
|
||||
- small-saas/dataset/subscription-ledger
|
||||
controls:
|
||||
- small-saas/control/namespace-per-tenant
|
||||
policies:
|
||||
- small-saas/policy/tenant-isolation
|
||||
evidence_ids:
|
||||
- small-saas/evidence/access-review-2026-05
|
||||
relationships:
|
||||
- type: part_of
|
||||
target: small-saas/system/billing-system
|
||||
- type: owned_by
|
||||
target: small-saas/team/platform
|
||||
- type: stores
|
||||
target: small-saas/dataset/subscription-ledger
|
||||
- type: deployed_as
|
||||
target: small-saas/deployment/production
|
||||
- type: governed_by
|
||||
target: small-saas/policy/tenant-isolation
|
||||
- type: protected_by
|
||||
target: small-saas/control/namespace-per-tenant
|
||||
@@ -0,0 +1,17 @@
|
||||
id: small-saas/system/billing-system
|
||||
kind: system
|
||||
title: Small SaaS Billing System
|
||||
profile: small-saas
|
||||
service_ids:
|
||||
- small-saas/service/billing-portal
|
||||
tenant_ids:
|
||||
- small-saas/tenant/acme
|
||||
- small-saas/tenant/globex
|
||||
owner_team: small-saas/team/platform
|
||||
relationships:
|
||||
- type: includes
|
||||
target: small-saas/service/billing-portal
|
||||
- type: serves
|
||||
target: small-saas/tenant/acme
|
||||
- type: serves
|
||||
target: small-saas/tenant/globex
|
||||
@@ -0,0 +1,16 @@
|
||||
id: small-saas/task/onboard-tenant
|
||||
kind: task
|
||||
title: Onboard Tenant
|
||||
profile: small-saas
|
||||
owner_team: small-saas/team/platform
|
||||
status: ready
|
||||
target_tenant: small-saas/tenant/acme
|
||||
evidence_ids:
|
||||
- small-saas/evidence/access-review-2026-05
|
||||
relationships:
|
||||
- type: owned_by
|
||||
target: small-saas/team/platform
|
||||
- type: changes
|
||||
target: small-saas/tenant/acme
|
||||
- type: governed_by
|
||||
target: small-saas/policy/tenant-isolation
|
||||
14
infospace/profiles/small-saas/artifacts/team.platform.yaml
Normal file
14
infospace/profiles/small-saas/artifacts/team.platform.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
id: small-saas/team/platform
|
||||
kind: team
|
||||
title: Platform Team
|
||||
profile: small-saas
|
||||
owner_user: small-saas/user/ada-admin
|
||||
responsibilities:
|
||||
- service ownership
|
||||
- tenant onboarding
|
||||
- access review
|
||||
relationships:
|
||||
- type: owns
|
||||
target: small-saas/service/billing-portal
|
||||
- type: performs
|
||||
target: small-saas/task/onboard-tenant
|
||||
12
infospace/profiles/small-saas/artifacts/tenant.acme.yaml
Normal file
12
infospace/profiles/small-saas/artifacts/tenant.acme.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
id: small-saas/tenant/acme
|
||||
kind: tenant
|
||||
title: Acme Tenant
|
||||
profile: small-saas
|
||||
namespace: tenant-acme
|
||||
data_partition: subscription-ledger:tenant=acme
|
||||
primary_user: small-saas/user/ada-admin
|
||||
relationships:
|
||||
- type: represented_by
|
||||
target: small-saas/user/ada-admin
|
||||
- type: isolated_by
|
||||
target: small-saas/control/namespace-per-tenant
|
||||
@@ -0,0 +1,9 @@
|
||||
id: small-saas/tenant/globex
|
||||
kind: tenant
|
||||
title: Globex Tenant
|
||||
profile: small-saas
|
||||
namespace: tenant-globex
|
||||
data_partition: subscription-ledger:tenant=globex
|
||||
relationships:
|
||||
- type: isolated_by
|
||||
target: small-saas/control/namespace-per-tenant
|
||||
19
infospace/profiles/small-saas/artifacts/user.ada-admin.yaml
Normal file
19
infospace/profiles/small-saas/artifacts/user.ada-admin.yaml
Normal file
@@ -0,0 +1,19 @@
|
||||
id: small-saas/user/ada-admin
|
||||
kind: user
|
||||
title: Ada Admin
|
||||
profile: small-saas
|
||||
person_type: human
|
||||
teams:
|
||||
- small-saas/team/platform
|
||||
access_grants:
|
||||
- role: tenant-admin
|
||||
tenant_id: small-saas/tenant/acme
|
||||
policy_id: small-saas/policy/tenant-isolation
|
||||
evidence_id: small-saas/evidence/access-review-2026-05
|
||||
relationships:
|
||||
- type: member_of
|
||||
target: small-saas/team/platform
|
||||
- type: has_access_under
|
||||
target: small-saas/policy/tenant-isolation
|
||||
- type: access_evidenced_by
|
||||
target: small-saas/evidence/access-review-2026-05
|
||||
112
infospace/profiles/small-saas/profile.yaml
Normal file
112
infospace/profiles/small-saas/profile.yaml
Normal file
@@ -0,0 +1,112 @@
|
||||
id: small-saas
|
||||
kind: profile
|
||||
profile: small-saas
|
||||
title: Small SaaS System Profile
|
||||
scope: A compact tenant-aware SaaS service with users, teams, data, access, deployment, governance evidence, and incident handling.
|
||||
status: proof
|
||||
conformance_level: profile-proof
|
||||
assumptions:
|
||||
- The SaaS product has a single service boundary and two example tenants.
|
||||
- Tenants are separated by namespace and data partitioning claims.
|
||||
- User management is represented through users, teams, access grants, policies, controls, and evidence.
|
||||
- Runtime concerns are represented by one production deployment.
|
||||
required_standards:
|
||||
- kernel/itc-core
|
||||
- model/landscape
|
||||
- model/organization
|
||||
- model/governance
|
||||
- model/task
|
||||
- model/access-control
|
||||
- model/security
|
||||
- model/data
|
||||
- model/devsecops
|
||||
- model/network
|
||||
- model/observability
|
||||
- standard/tagging
|
||||
- standard/caring
|
||||
required_concepts:
|
||||
service:
|
||||
status: required
|
||||
model: model/landscape
|
||||
system:
|
||||
status: required
|
||||
model: model/landscape
|
||||
tenant:
|
||||
status: required
|
||||
model: model/organization
|
||||
user:
|
||||
status: required
|
||||
model: model/organization
|
||||
team:
|
||||
status: required
|
||||
model: model/organization
|
||||
dataset:
|
||||
status: required
|
||||
model: model/data
|
||||
deployment:
|
||||
status: required
|
||||
model: model/devsecops
|
||||
task:
|
||||
status: required
|
||||
model: model/task
|
||||
policy:
|
||||
status: required
|
||||
model: model/governance
|
||||
control:
|
||||
status: required
|
||||
model: model/security
|
||||
evidence:
|
||||
status: required
|
||||
model: model/observability
|
||||
incident:
|
||||
status: required
|
||||
model: model/security
|
||||
optional_concepts:
|
||||
billing-plan:
|
||||
status: optional
|
||||
model: model/data
|
||||
notification:
|
||||
status: optional
|
||||
model: model/observability
|
||||
out_of_scope:
|
||||
- multi-region disaster recovery
|
||||
- tenant-managed encryption keys
|
||||
- marketplace billing integrations
|
||||
artifact_ids:
|
||||
- profile/small-saas
|
||||
- small-saas/service/billing-portal
|
||||
- small-saas/system/billing-system
|
||||
- small-saas/tenant/acme
|
||||
- small-saas/tenant/globex
|
||||
- small-saas/user/ada-admin
|
||||
- small-saas/team/platform
|
||||
- small-saas/dataset/subscription-ledger
|
||||
- small-saas/deployment/production
|
||||
- small-saas/task/onboard-tenant
|
||||
- small-saas/policy/tenant-isolation
|
||||
- small-saas/control/namespace-per-tenant
|
||||
- small-saas/evidence/access-review-2026-05
|
||||
- small-saas/incident/cross-tenant-access-attempt
|
||||
validation_rules:
|
||||
required_artifact_kinds:
|
||||
- service
|
||||
- system
|
||||
- tenant
|
||||
- user
|
||||
- team
|
||||
- dataset
|
||||
- deployment
|
||||
- task
|
||||
- policy
|
||||
- control
|
||||
- evidence
|
||||
- incident
|
||||
service_ownership: required
|
||||
tenant_namespace_separation: required
|
||||
user_management_trace: required
|
||||
access_control_trace: required
|
||||
governance_evidence: required
|
||||
demo_commands:
|
||||
- PYTHONPATH=src python3 -m info_tech_canon profile inspect small-saas
|
||||
- PYTHONPATH=src python3 -m info_tech_canon profile validate small-saas
|
||||
- PYTHONPATH=src python3 -m info_tech_canon profile graph small-saas
|
||||
44
infospace/reports/small-saas-profile-proof.md
Normal file
44
infospace/reports/small-saas-profile-proof.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# Small SaaS Profile Proof
|
||||
|
||||
**Workplan:** ITC-WP-0004
|
||||
**Profile:** `small-saas`
|
||||
**Status:** executable proof
|
||||
|
||||
## Purpose
|
||||
|
||||
The `small-saas` profile demonstrates that the canon can guide a practical
|
||||
service shape before the larger CARING benchmark exists. It connects service
|
||||
ownership, users, tenants, access, data, runtime, deployment, governance,
|
||||
observability, and task tracking.
|
||||
|
||||
## Validation Surface
|
||||
|
||||
```bash
|
||||
PYTHONPATH=src python3 -m info_tech_canon profile inspect small-saas
|
||||
PYTHONPATH=src python3 -m info_tech_canon profile validate small-saas
|
||||
PYTHONPATH=src python3 -m info_tech_canon profile graph small-saas
|
||||
```
|
||||
|
||||
## Graph Slice
|
||||
|
||||
The profile graph includes the profile artifact, the small SaaS example
|
||||
artifacts, and their direct canon anchors.
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
profile_small_saas["profile/small-saas"] -->|conforms_to| core["kernel/itc-core"]
|
||||
service["small-saas/service/billing-portal"] -->|part_of| system["small-saas/system/billing-system"]
|
||||
service -->|owned_by| team["small-saas/team/platform"]
|
||||
service -->|governed_by| policy["small-saas/policy/tenant-isolation"]
|
||||
service -->|protected_by| control["small-saas/control/namespace-per-tenant"]
|
||||
deployment["small-saas/deployment/production"] -->|separates| acme["small-saas/tenant/acme"]
|
||||
deployment -->|separates| globex["small-saas/tenant/globex"]
|
||||
user["small-saas/user/ada-admin"] -->|has_access_under| policy
|
||||
policy -->|evidenced_by| evidence["small-saas/evidence/access-review-2026-05"]
|
||||
incident["small-saas/incident/cross-tenant-access-attempt"] -->|constrained_by| control
|
||||
```
|
||||
|
||||
## Result
|
||||
|
||||
The proof is suitable as a baseline for the upcoming `user-engine` evaluation
|
||||
pack and for `railiance-fabric` entity/edge capture comparisons.
|
||||
@@ -1,14 +1,14 @@
|
||||
{
|
||||
"details": {
|
||||
"artifact_count": 15,
|
||||
"relationship_count": 45
|
||||
"artifact_count": 29,
|
||||
"relationship_count": 113
|
||||
},
|
||||
"errors": [],
|
||||
"metrics": {
|
||||
"coherence_components": 1.0,
|
||||
"consistency_cycles": 0.0,
|
||||
"coverage_ratio": 1.0,
|
||||
"granularity_entropy": 1.103307408607834,
|
||||
"granularity_entropy": 1.7490339557881076,
|
||||
"redundancy_ratio": 0.0
|
||||
},
|
||||
"ok": true,
|
||||
@@ -17,10 +17,6 @@
|
||||
"code": "missing_optional_concepts_dir",
|
||||
"path": "infospace/concepts"
|
||||
},
|
||||
{
|
||||
"code": "empty_optional_collection",
|
||||
"path": "infospace/profiles"
|
||||
},
|
||||
{
|
||||
"code": "empty_optional_collection",
|
||||
"path": "infospace/patterns"
|
||||
@@ -32,10 +28,6 @@
|
||||
{
|
||||
"code": "empty_optional_collection",
|
||||
"path": "infospace/assimilation"
|
||||
},
|
||||
{
|
||||
"code": "empty_optional_collection",
|
||||
"path": "infospace/examples"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# By Concept
|
||||
|
||||
Concept count: **30**
|
||||
Concept count: **44**
|
||||
|
||||
| Concept | Owner | Source |
|
||||
| --- | --- | --- |
|
||||
@@ -19,6 +19,20 @@ Concept count: **30**
|
||||
| InfoTechCanon Organization Model | `model/organization` | `artifact_title` |
|
||||
| InfoTechCanon Security Model | `model/security` | `artifact_title` |
|
||||
| InfoTechCanon Task Model | `model/task` | `artifact_title` |
|
||||
| Small SaaS System Profile | `profile/small-saas` | `artifact_title` |
|
||||
| Namespace Per Tenant Control | `small-saas/control/namespace-per-tenant` | `artifact_title` |
|
||||
| Subscription Ledger Dataset | `small-saas/dataset/subscription-ledger` | `artifact_title` |
|
||||
| Production Deployment | `small-saas/deployment/production` | `artifact_title` |
|
||||
| Access Review 2026-05 | `small-saas/evidence/access-review-2026-05` | `artifact_title` |
|
||||
| Cross-Tenant Access Attempt | `small-saas/incident/cross-tenant-access-attempt` | `artifact_title` |
|
||||
| Tenant Isolation Policy | `small-saas/policy/tenant-isolation` | `artifact_title` |
|
||||
| Billing Portal Service | `small-saas/service/billing-portal` | `artifact_title` |
|
||||
| Small SaaS Billing System | `small-saas/system/billing-system` | `artifact_title` |
|
||||
| Onboard Tenant | `small-saas/task/onboard-tenant` | `artifact_title` |
|
||||
| Platform Team | `small-saas/team/platform` | `artifact_title` |
|
||||
| Acme Tenant | `small-saas/tenant/acme` | `artifact_title` |
|
||||
| Globex Tenant | `small-saas/tenant/globex` | `artifact_title` |
|
||||
| Ada Admin | `small-saas/user/ada-admin` | `artifact_title` |
|
||||
| InfoTechCanon CARING Access Governance Standard | `standard/caring` | `artifact_title` |
|
||||
| CARINGAccessDescriptor | `standard/caring` | `frontmatter.owned_concepts` |
|
||||
| CARINGCanonicalRole | `standard/caring` | `frontmatter.owned_concepts` |
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
- `model/organization` via `conforms_to`
|
||||
- `model/security` via `conforms_to`
|
||||
- `model/task` via `conforms_to`
|
||||
- `profile/small-saas` via `conforms_to`
|
||||
- `standard/caring` via `conforms_to`
|
||||
- `standard/tagging` via `conforms_to`
|
||||
|
||||
@@ -23,16 +24,22 @@
|
||||
|
||||
- `kernel/itc-kernel-map` via `maps`
|
||||
- `model/security` via `uses`
|
||||
- `profile/small-saas` via `requires`
|
||||
- `small-saas/user/ada-admin` via `uses`
|
||||
- `standard/caring` via `imports`
|
||||
|
||||
## `model/data`
|
||||
|
||||
- `kernel/itc-kernel-map` via `maps`
|
||||
- `profile/small-saas` via `requires`
|
||||
- `small-saas/dataset/subscription-ledger` via `uses`
|
||||
- `standard/caring` via `imports`
|
||||
|
||||
## `model/devsecops`
|
||||
|
||||
- `kernel/itc-kernel-map` via `maps`
|
||||
- `profile/small-saas` via `requires`
|
||||
- `small-saas/deployment/production` via `uses`
|
||||
- `standard/caring` via `imports`
|
||||
|
||||
## `model/governance`
|
||||
@@ -40,6 +47,8 @@
|
||||
- `kernel/itc-kernel-map` via `maps`
|
||||
- `model/access-control` via `uses`
|
||||
- `model/data` via `uses`
|
||||
- `profile/small-saas` via `requires`
|
||||
- `small-saas/policy/tenant-isolation` via `uses`
|
||||
- `standard/caring` via `imports`
|
||||
|
||||
## `model/information-space`
|
||||
@@ -49,21 +58,33 @@
|
||||
## `model/landscape`
|
||||
|
||||
- `kernel/itc-kernel-map` via `maps`
|
||||
- `profile/small-saas` via `requires`
|
||||
- `small-saas/service/billing-portal` via `uses`
|
||||
- `small-saas/system/billing-system` via `uses`
|
||||
|
||||
## `model/network`
|
||||
|
||||
- `kernel/itc-kernel-map` via `maps`
|
||||
- `profile/small-saas` via `requires`
|
||||
- `small-saas/deployment/production` via `uses`
|
||||
- `standard/caring` via `imports`
|
||||
|
||||
## `model/observability`
|
||||
|
||||
- `kernel/itc-kernel-map` via `maps`
|
||||
- `profile/small-saas` via `requires`
|
||||
- `small-saas/evidence/access-review-2026-05` via `uses`
|
||||
- `standard/caring` via `imports`
|
||||
|
||||
## `model/organization`
|
||||
|
||||
- `kernel/itc-kernel-map` via `maps`
|
||||
- `model/access-control` via `uses`
|
||||
- `profile/small-saas` via `requires`
|
||||
- `small-saas/team/platform` via `uses`
|
||||
- `small-saas/tenant/acme` via `uses`
|
||||
- `small-saas/tenant/globex` via `uses`
|
||||
- `small-saas/user/ada-admin` via `uses`
|
||||
- `standard/caring` via `imports`
|
||||
|
||||
## `model/security`
|
||||
@@ -71,20 +92,97 @@
|
||||
- `kernel/itc-kernel-map` via `maps`
|
||||
- `model/devsecops` via `uses`
|
||||
- `model/network` via `uses`
|
||||
- `profile/small-saas` via `requires`
|
||||
- `small-saas/control/namespace-per-tenant` via `uses`
|
||||
- `small-saas/incident/cross-tenant-access-attempt` via `uses`
|
||||
- `standard/caring` via `imports`
|
||||
|
||||
## `model/task`
|
||||
|
||||
- `kernel/itc-kernel-map` via `maps`
|
||||
- `model/observability` via `uses`
|
||||
- `profile/small-saas` via `requires`
|
||||
- `small-saas/task/onboard-tenant` via `uses`
|
||||
- `standard/caring` via `imports`
|
||||
- `standard/tagging` via `imports`
|
||||
|
||||
## `profile/small-saas`
|
||||
|
||||
- `small-saas/control/namespace-per-tenant` via `instantiates`
|
||||
- `small-saas/dataset/subscription-ledger` via `instantiates`
|
||||
- `small-saas/deployment/production` via `instantiates`
|
||||
- `small-saas/evidence/access-review-2026-05` via `instantiates`
|
||||
- `small-saas/incident/cross-tenant-access-attempt` via `instantiates`
|
||||
- `small-saas/policy/tenant-isolation` via `instantiates`
|
||||
- `small-saas/service/billing-portal` via `instantiates`
|
||||
- `small-saas/system/billing-system` via `instantiates`
|
||||
- `small-saas/task/onboard-tenant` via `instantiates`
|
||||
- `small-saas/team/platform` via `instantiates`
|
||||
- `small-saas/tenant/acme` via `instantiates`
|
||||
- `small-saas/tenant/globex` via `instantiates`
|
||||
- `small-saas/user/ada-admin` via `instantiates`
|
||||
|
||||
## `small-saas/control/namespace-per-tenant`
|
||||
|
||||
- `small-saas/deployment/production` via `implements`
|
||||
- `small-saas/incident/cross-tenant-access-attempt` via `constrained_by`
|
||||
- `small-saas/policy/tenant-isolation` via `requires`
|
||||
- `small-saas/tenant/acme` via `isolated_by`
|
||||
- `small-saas/tenant/globex` via `isolated_by`
|
||||
|
||||
## `small-saas/evidence/access-review-2026-05`
|
||||
|
||||
- `small-saas/control/namespace-per-tenant` via `evidenced_by`
|
||||
- `small-saas/incident/cross-tenant-access-attempt` via `evidenced_by`
|
||||
- `small-saas/policy/tenant-isolation` via `evidenced_by`
|
||||
- `small-saas/user/ada-admin` via `access_evidenced_by`
|
||||
|
||||
## `small-saas/policy/tenant-isolation`
|
||||
|
||||
- `small-saas/dataset/subscription-ledger` via `governed_by`
|
||||
- `small-saas/task/onboard-tenant` via `governed_by`
|
||||
- `small-saas/user/ada-admin` via `has_access_under`
|
||||
|
||||
## `small-saas/service/billing-portal`
|
||||
|
||||
- `small-saas/dataset/subscription-ledger` via `owned_by`
|
||||
- `small-saas/deployment/production` via `deploys`
|
||||
|
||||
## `small-saas/system/billing-system`
|
||||
|
||||
- `small-saas/service/billing-portal` via `part_of`
|
||||
|
||||
## `small-saas/team/platform`
|
||||
|
||||
- `small-saas/service/billing-portal` via `owned_by`
|
||||
- `small-saas/task/onboard-tenant` via `owned_by`
|
||||
- `small-saas/user/ada-admin` via `member_of`
|
||||
|
||||
## `small-saas/tenant/acme`
|
||||
|
||||
- `small-saas/dataset/subscription-ledger` via `partitioned_for`
|
||||
- `small-saas/deployment/production` via `separates`
|
||||
- `small-saas/system/billing-system` via `serves`
|
||||
- `small-saas/task/onboard-tenant` via `changes`
|
||||
|
||||
## `small-saas/tenant/globex`
|
||||
|
||||
- `small-saas/dataset/subscription-ledger` via `partitioned_for`
|
||||
- `small-saas/deployment/production` via `separates`
|
||||
- `small-saas/system/billing-system` via `serves`
|
||||
|
||||
## `small-saas/user/ada-admin`
|
||||
|
||||
- `small-saas/tenant/acme` via `represented_by`
|
||||
|
||||
## `standard/caring`
|
||||
|
||||
- `kernel/itc-kernel-map` via `maps`
|
||||
- `profile/small-saas` via `requires`
|
||||
- `small-saas/control/namespace-per-tenant` via `uses`
|
||||
|
||||
## `standard/tagging`
|
||||
|
||||
- `kernel/itc-kernel-map` via `maps`
|
||||
- `profile/small-saas` via `requires`
|
||||
- `standard/caring` via `imports`
|
||||
|
||||
@@ -2,4 +2,6 @@
|
||||
|
||||
# By Profile
|
||||
|
||||
No profiles have been registered yet.
|
||||
## small-saas
|
||||
|
||||
- Path: `profiles/small-saas/profile.yaml`
|
||||
|
||||
@@ -2,20 +2,34 @@
|
||||
|
||||
# Import Matrix
|
||||
|
||||
| Artifact | `kernel/itc-core` | `kernel/itc-kernel-map` | `model/access-control` | `model/data` | `model/devsecops` | `model/governance` | `model/information-space` | `model/landscape` | `model/network` | `model/observability` | `model/organization` | `model/security` | `model/task` | `standard/caring` | `standard/tagging` |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| `kernel/itc-core` | | | | | | | | | | | | | | | |
|
||||
| `kernel/itc-kernel-map` | `maps` | | `maps` | `maps` | `maps` | `maps` | `maps` | `maps` | `maps` | `maps` | `maps` | `maps` | `maps` | `maps` | `maps` |
|
||||
| `model/access-control` | `conforms_to` | | | | | `uses` | | | | | `uses` | | | | |
|
||||
| `model/data` | `conforms_to` | | | | | `uses` | | | | | | | | | |
|
||||
| `model/devsecops` | `conforms_to` | | | | | | | | | | | `uses` | | | |
|
||||
| `model/governance` | `conforms_to` | | | | | | | | | | | | | | |
|
||||
| `model/information-space` | `conforms_to` | | | | | | | | | | | | | | |
|
||||
| `model/landscape` | `conforms_to` | | | | | | | | | | | | | | |
|
||||
| `model/network` | `conforms_to` | | | | | | | | | | | `uses` | | | |
|
||||
| `model/observability` | `conforms_to` | | | | | | | | | | | | `uses` | | |
|
||||
| `model/organization` | `conforms_to` | | | | | | | | | | | | | | |
|
||||
| `model/security` | `conforms_to` | | `uses` | | | | | | | | | | | | |
|
||||
| `model/task` | `conforms_to` | | | | | | | | | | | | | | |
|
||||
| `standard/caring` | `conforms_to` | | `imports` | `imports` | `imports` | `imports` | | | `imports` | `imports` | `imports` | `imports` | `imports` | | `imports` |
|
||||
| `standard/tagging` | `conforms_to` | | | | | | | | | | | | `imports` | | |
|
||||
| Artifact | `kernel/itc-core` | `kernel/itc-kernel-map` | `model/access-control` | `model/data` | `model/devsecops` | `model/governance` | `model/information-space` | `model/landscape` | `model/network` | `model/observability` | `model/organization` | `model/security` | `model/task` | `profile/small-saas` | `small-saas/control/namespace-per-tenant` | `small-saas/dataset/subscription-ledger` | `small-saas/deployment/production` | `small-saas/evidence/access-review-2026-05` | `small-saas/incident/cross-tenant-access-attempt` | `small-saas/policy/tenant-isolation` | `small-saas/service/billing-portal` | `small-saas/system/billing-system` | `small-saas/task/onboard-tenant` | `small-saas/team/platform` | `small-saas/tenant/acme` | `small-saas/tenant/globex` | `small-saas/user/ada-admin` | `standard/caring` | `standard/tagging` |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| `kernel/itc-core` | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
| `kernel/itc-kernel-map` | `maps` | | `maps` | `maps` | `maps` | `maps` | `maps` | `maps` | `maps` | `maps` | `maps` | `maps` | `maps` | | | | | | | | | | | | | | | `maps` | `maps` |
|
||||
| `model/access-control` | `conforms_to` | | | | | `uses` | | | | | `uses` | | | | | | | | | | | | | | | | | | |
|
||||
| `model/data` | `conforms_to` | | | | | `uses` | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
| `model/devsecops` | `conforms_to` | | | | | | | | | | | `uses` | | | | | | | | | | | | | | | | | |
|
||||
| `model/governance` | `conforms_to` | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
| `model/information-space` | `conforms_to` | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
| `model/landscape` | `conforms_to` | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
| `model/network` | `conforms_to` | | | | | | | | | | | `uses` | | | | | | | | | | | | | | | | | |
|
||||
| `model/observability` | `conforms_to` | | | | | | | | | | | | `uses` | | | | | | | | | | | | | | | | |
|
||||
| `model/organization` | `conforms_to` | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
| `model/security` | `conforms_to` | | `uses` | | | | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
| `model/task` | `conforms_to` | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
| `profile/small-saas` | `conforms_to` | | `requires` | `requires` | `requires` | `requires` | | `requires` | `requires` | `requires` | `requires` | `requires` | `requires` | | | | | | | | | | | | | | | `requires` | `requires` |
|
||||
| `small-saas/control/namespace-per-tenant` | | | | | | | | | | | | `uses` | | `instantiates` | | | | `evidenced_by` | | | | | | | | | | `uses` | |
|
||||
| `small-saas/dataset/subscription-ledger` | | | | `uses` | | | | | | | | | | `instantiates` | | | | | | `governed_by` | `owned_by` | | | | `partitioned_for` | `partitioned_for` | | | |
|
||||
| `small-saas/deployment/production` | | | | | `uses` | | | | `uses` | | | | | `instantiates` | `implements` | | | | | | `deploys` | | | | `separates` | `separates` | | | |
|
||||
| `small-saas/evidence/access-review-2026-05` | | | | | | | | | | `uses` | | | | `instantiates` | | | | | | | | | | | | | | | |
|
||||
| `small-saas/incident/cross-tenant-access-attempt` | | | | | | | | | | | | `uses` | | `instantiates` | `constrained_by` | | | `evidenced_by` | | | | | | | | | | | |
|
||||
| `small-saas/policy/tenant-isolation` | | | | | | `uses` | | | | | | | | `instantiates` | `requires` | | | `evidenced_by` | | | | | | | | | | | |
|
||||
| `small-saas/service/billing-portal` | | | | | | | | `uses` | | | | | | `instantiates` | | | | | | | | `part_of` | | `owned_by` | | | | | |
|
||||
| `small-saas/system/billing-system` | | | | | | | | `uses` | | | | | | `instantiates` | | | | | | | | | | | `serves` | `serves` | | | |
|
||||
| `small-saas/task/onboard-tenant` | | | | | | | | | | | | | `uses` | `instantiates` | | | | | | `governed_by` | | | | `owned_by` | `changes` | | | | |
|
||||
| `small-saas/team/platform` | | | | | | | | | | | `uses` | | | `instantiates` | | | | | | | | | | | | | | | |
|
||||
| `small-saas/tenant/acme` | | | | | | | | | | | `uses` | | | `instantiates` | `isolated_by` | | | | | | | | | | | | `represented_by` | | |
|
||||
| `small-saas/tenant/globex` | | | | | | | | | | | `uses` | | | `instantiates` | `isolated_by` | | | | | | | | | | | | | | |
|
||||
| `small-saas/user/ada-admin` | | | `uses` | | | | | | | | `uses` | | | `instantiates` | | | | `access_evidenced_by` | | `has_access_under` | | | | `member_of` | | | | | |
|
||||
| `standard/caring` | `conforms_to` | | `imports` | `imports` | `imports` | `imports` | | | `imports` | `imports` | `imports` | `imports` | `imports` | | | | | | | | | | | | | | | | `imports` |
|
||||
| `standard/tagging` | `conforms_to` | | | | | | | | | | | | `imports` | | | | | | | | | | | | | | | | |
|
||||
|
||||
@@ -3,17 +3,37 @@
|
||||
# Kernel Overview
|
||||
|
||||
- Infospace: `canon`
|
||||
- Artifacts: 15
|
||||
- Artifacts: 29
|
||||
|
||||
## Artifact Kinds
|
||||
|
||||
- `kernel`: 2
|
||||
- `model`: 11
|
||||
- `profile`: 1
|
||||
- `profile-artifact`: 13
|
||||
- `standard`: 2
|
||||
|
||||
## Relationship Types
|
||||
|
||||
- `conforms_to`: 13
|
||||
- `access_evidenced_by`: 1
|
||||
- `changes`: 1
|
||||
- `conforms_to`: 14
|
||||
- `constrained_by`: 1
|
||||
- `deploys`: 1
|
||||
- `evidenced_by`: 3
|
||||
- `governed_by`: 2
|
||||
- `has_access_under`: 1
|
||||
- `implements`: 1
|
||||
- `imports`: 11
|
||||
- `instantiates`: 13
|
||||
- `isolated_by`: 2
|
||||
- `maps`: 14
|
||||
- `uses`: 7
|
||||
- `member_of`: 1
|
||||
- `owned_by`: 3
|
||||
- `part_of`: 1
|
||||
- `partitioned_for`: 2
|
||||
- `represented_by`: 1
|
||||
- `requires`: 13
|
||||
- `separates`: 2
|
||||
- `serves`: 2
|
||||
- `uses`: 23
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Repository Tree
|
||||
|
||||
File count: **50**
|
||||
File count: **67**
|
||||
|
||||
- `README.md`
|
||||
- `agent/README.md`
|
||||
@@ -10,6 +10,8 @@ File count: **50**
|
||||
- `artifacts/index.yaml`
|
||||
- `assimilation/README.md`
|
||||
- `examples/README.md`
|
||||
- `examples/small-saas/README.md`
|
||||
- `examples/small-saas/demo-commands.yaml`
|
||||
- `indexes/README.md`
|
||||
- `indexes/artifact-tree.yaml`
|
||||
- `indexes/concept-ownership.yaml`
|
||||
@@ -31,7 +33,22 @@ File count: **50**
|
||||
- `models/task/InfoTechCanonTaskModel.md`
|
||||
- `patterns/README.md`
|
||||
- `profiles/README.md`
|
||||
- `profiles/small-saas/artifacts/control.namespace-per-tenant.yaml`
|
||||
- `profiles/small-saas/artifacts/dataset.subscription-ledger.yaml`
|
||||
- `profiles/small-saas/artifacts/deployment.production.yaml`
|
||||
- `profiles/small-saas/artifacts/evidence.access-review-2026-05.yaml`
|
||||
- `profiles/small-saas/artifacts/incident.cross-tenant-access-attempt.yaml`
|
||||
- `profiles/small-saas/artifacts/policy.tenant-isolation.yaml`
|
||||
- `profiles/small-saas/artifacts/service.billing-portal.yaml`
|
||||
- `profiles/small-saas/artifacts/system.billing-system.yaml`
|
||||
- `profiles/small-saas/artifacts/task.onboard-tenant.yaml`
|
||||
- `profiles/small-saas/artifacts/team.platform.yaml`
|
||||
- `profiles/small-saas/artifacts/tenant.acme.yaml`
|
||||
- `profiles/small-saas/artifacts/tenant.globex.yaml`
|
||||
- `profiles/small-saas/artifacts/user.ada-admin.yaml`
|
||||
- `profiles/small-saas/profile.yaml`
|
||||
- `reports/scaffold-placement.md`
|
||||
- `reports/small-saas-profile-proof.md`
|
||||
- `schemas/README.md`
|
||||
- `schemas/agent-brief.schema.yaml`
|
||||
- `schemas/assimilation.schema.yaml`
|
||||
|
||||
@@ -11,7 +11,9 @@ from .service import (
|
||||
list_models,
|
||||
list_standards,
|
||||
list_views,
|
||||
profile_graph,
|
||||
profile_inspect,
|
||||
profile_validate,
|
||||
read_view,
|
||||
validate_canon,
|
||||
write_validation_report,
|
||||
@@ -28,7 +30,9 @@ __all__ = [
|
||||
"list_models",
|
||||
"list_standards",
|
||||
"list_views",
|
||||
"profile_graph",
|
||||
"profile_inspect",
|
||||
"profile_validate",
|
||||
"read_view",
|
||||
"validate_canon",
|
||||
"write_validation_report",
|
||||
|
||||
@@ -15,7 +15,9 @@ from .service import (
|
||||
list_models,
|
||||
list_standards,
|
||||
list_views,
|
||||
profile_graph,
|
||||
profile_inspect,
|
||||
profile_validate,
|
||||
read_view,
|
||||
validate_canon,
|
||||
)
|
||||
@@ -96,6 +98,14 @@ def _route(
|
||||
if path.startswith("/profiles/") and path.endswith("/inspect"):
|
||||
profile = path.removeprefix("/profiles/").removesuffix("/inspect").strip("/")
|
||||
return HTTPStatus.OK, profile_inspect(profile, root)
|
||||
if path.startswith("/profiles/") and path.endswith("/validate"):
|
||||
profile = path.removeprefix("/profiles/").removesuffix("/validate").strip("/")
|
||||
payload = profile_validate(profile, root)
|
||||
return (HTTPStatus.OK if payload["ok"] else HTTPStatus.BAD_REQUEST), payload
|
||||
if path.startswith("/profiles/") and path.endswith("/graph"):
|
||||
profile = path.removeprefix("/profiles/").removesuffix("/graph").strip("/")
|
||||
graph_format = _first(query, "format") or "json"
|
||||
return HTTPStatus.OK, profile_graph(profile, root, output_format=graph_format)
|
||||
return HTTPStatus.NOT_FOUND, {
|
||||
"ok": False,
|
||||
"error": {
|
||||
|
||||
@@ -19,7 +19,9 @@ from .service import (
|
||||
list_models,
|
||||
list_standards,
|
||||
list_views,
|
||||
profile_graph,
|
||||
profile_inspect,
|
||||
profile_validate,
|
||||
read_view,
|
||||
validate_canon,
|
||||
write_validation_report,
|
||||
@@ -81,6 +83,13 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
profile_inspect_cmd = profile_sub.add_parser("inspect", help="Inspect a profile")
|
||||
profile_inspect_cmd.add_argument("profile")
|
||||
profile_inspect_cmd.set_defaults(handler=_profile_inspect)
|
||||
profile_validate_cmd = profile_sub.add_parser("validate", help="Validate a profile")
|
||||
profile_validate_cmd.add_argument("profile")
|
||||
profile_validate_cmd.set_defaults(handler=_profile_validate)
|
||||
profile_graph_cmd = profile_sub.add_parser("graph", help="Export a profile graph")
|
||||
profile_graph_cmd.add_argument("profile")
|
||||
profile_graph_cmd.add_argument("--format", choices=["json", "mermaid"], default="json")
|
||||
profile_graph_cmd.set_defaults(handler=_profile_graph)
|
||||
|
||||
api = sub.add_parser("api", help="Run the read-only local API")
|
||||
api.add_argument("--host", default="127.0.0.1")
|
||||
@@ -168,6 +177,14 @@ def _profile_inspect(args: argparse.Namespace) -> dict[str, Any]:
|
||||
return profile_inspect(args.profile, _root(args))
|
||||
|
||||
|
||||
def _profile_validate(args: argparse.Namespace) -> dict[str, Any]:
|
||||
return profile_validate(args.profile, _root(args))
|
||||
|
||||
|
||||
def _profile_graph(args: argparse.Namespace) -> dict[str, Any]:
|
||||
return profile_graph(args.profile, _root(args), output_format=args.format)
|
||||
|
||||
|
||||
def _api(args: argparse.Namespace) -> dict[str, Any]:
|
||||
serve(host=args.host, port=args.port, root=_root(args))
|
||||
return {}
|
||||
|
||||
402
src/info_tech_canon/profiles.py
Normal file
402
src/info_tech_canon/profiles.py
Normal file
@@ -0,0 +1,402 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import asdict
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import yaml
|
||||
|
||||
from .bench import export_mermaid, relationship_summary
|
||||
|
||||
|
||||
REQUIRED_SMALL_SAAS_KINDS = {
|
||||
"service",
|
||||
"system",
|
||||
"tenant",
|
||||
"user",
|
||||
"team",
|
||||
"dataset",
|
||||
"deployment",
|
||||
"task",
|
||||
"policy",
|
||||
"control",
|
||||
"evidence",
|
||||
"incident",
|
||||
}
|
||||
|
||||
|
||||
def inspect_profile(context: Any, profile: str) -> dict[str, Any]:
|
||||
definition = load_profile_definition(context, profile)
|
||||
records = profile_artifact_records(context, profile)
|
||||
return {
|
||||
"ok": True,
|
||||
"profile": definition,
|
||||
"path": str(profile_path(context, profile)),
|
||||
"artifact_count": len(records),
|
||||
"artifacts": [artifact.to_dict() for artifact in records],
|
||||
}
|
||||
|
||||
|
||||
def validate_profile(context: Any, profile: str) -> dict[str, Any]:
|
||||
definition = load_profile_definition(context, profile)
|
||||
records = profile_artifact_records(context, profile)
|
||||
payloads = load_profile_artifacts(context, records)
|
||||
errors: list[dict[str, Any]] = []
|
||||
warnings: list[dict[str, Any]] = []
|
||||
|
||||
_check_profile_definition(profile, definition, records, errors)
|
||||
_check_required_artifact_kinds(profile, payloads, errors)
|
||||
_check_artifact_payloads(profile, payloads, errors)
|
||||
_check_service_ownership(payloads, errors)
|
||||
_check_tenant_namespace_separation(payloads, errors)
|
||||
_check_user_management_and_access(payloads, errors)
|
||||
_check_governance_evidence(payloads, errors)
|
||||
|
||||
return {
|
||||
"ok": not errors,
|
||||
"profile": profile,
|
||||
"errors": errors,
|
||||
"warnings": warnings,
|
||||
"details": {
|
||||
"artifact_count": len(records),
|
||||
"payload_count": len(payloads),
|
||||
"kinds": _kind_counts(payloads),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def profile_graph(
|
||||
context: Any,
|
||||
profile: str,
|
||||
*,
|
||||
output_format: str = "json",
|
||||
) -> dict[str, Any]:
|
||||
records = profile_artifact_records(context, profile)
|
||||
record_ids = {artifact.id for artifact in records}
|
||||
include_ids = set(record_ids)
|
||||
for artifact in records:
|
||||
for relationship in artifact.relationships:
|
||||
target = relationship.get("target")
|
||||
if isinstance(target, str):
|
||||
include_ids.add(target)
|
||||
artifacts = [
|
||||
artifact for artifact in context.infospace.artifacts if artifact.id in include_ids
|
||||
]
|
||||
summary = relationship_summary(artifacts)
|
||||
if output_format == "mermaid":
|
||||
return {"ok": True, "profile": profile, "format": "mermaid", "graph": export_mermaid(summary)}
|
||||
if output_format != "json":
|
||||
raise ValueError(f"Unsupported graph format: {output_format}")
|
||||
return {
|
||||
"ok": True,
|
||||
"profile": profile,
|
||||
"format": "json",
|
||||
"graph": {
|
||||
"node_count": summary.node_count,
|
||||
"edge_count": summary.edge_count,
|
||||
"nodes": summary.nodes,
|
||||
"edges": [asdict(edge) for edge in summary.edges],
|
||||
"relationship_types": summary.relationship_types,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def profile_path(context: Any, profile: str) -> Path:
|
||||
return context.infospace_root / "profiles" / profile / "profile.yaml"
|
||||
|
||||
|
||||
def load_profile_definition(context: Any, profile: str) -> dict[str, Any]:
|
||||
path = profile_path(context, profile)
|
||||
with path.open("r", encoding="utf-8") as handle:
|
||||
data = yaml.safe_load(handle) or {}
|
||||
if not isinstance(data, dict):
|
||||
raise ValueError(f"Profile must be a YAML mapping: {profile}")
|
||||
return data
|
||||
|
||||
|
||||
def profile_artifact_records(context: Any, profile: str) -> list[Any]:
|
||||
return [
|
||||
artifact
|
||||
for artifact in context.infospace.artifacts
|
||||
if artifact.id == f"profile/{profile}"
|
||||
or artifact.provenance.get("profile") == profile
|
||||
]
|
||||
|
||||
|
||||
def load_profile_artifacts(context: Any, records: list[Any]) -> dict[str, dict[str, Any]]:
|
||||
payloads: dict[str, dict[str, Any]] = {}
|
||||
for artifact in records:
|
||||
path = context.infospace_root / artifact.path
|
||||
with path.open("r", encoding="utf-8") as handle:
|
||||
data = yaml.safe_load(handle) or {}
|
||||
if isinstance(data, dict):
|
||||
payloads[artifact.id] = data
|
||||
return payloads
|
||||
|
||||
|
||||
def _check_profile_definition(
|
||||
profile: str,
|
||||
definition: dict[str, Any],
|
||||
records: list[Any],
|
||||
errors: list[dict[str, Any]],
|
||||
) -> None:
|
||||
for field in ("id", "title", "scope", "conformance_level", "required_standards"):
|
||||
if not definition.get(field):
|
||||
errors.append(
|
||||
{
|
||||
"code": "missing_profile_field",
|
||||
"profile": profile,
|
||||
"field": field,
|
||||
}
|
||||
)
|
||||
declared = set(definition.get("artifact_ids") or [])
|
||||
actual = {artifact.id for artifact in records}
|
||||
missing = sorted(declared - actual)
|
||||
for artifact_id in missing:
|
||||
errors.append(
|
||||
{
|
||||
"code": "missing_profile_artifact_record",
|
||||
"profile": profile,
|
||||
"artifact_id": artifact_id,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _check_required_artifact_kinds(
|
||||
profile: str,
|
||||
payloads: dict[str, dict[str, Any]],
|
||||
errors: list[dict[str, Any]],
|
||||
) -> None:
|
||||
kinds = {payload.get("kind") for payload in payloads.values()}
|
||||
for kind in sorted(REQUIRED_SMALL_SAAS_KINDS - kinds):
|
||||
errors.append(
|
||||
{
|
||||
"code": "missing_required_profile_kind",
|
||||
"profile": profile,
|
||||
"kind": kind,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _check_artifact_payloads(
|
||||
profile: str,
|
||||
payloads: dict[str, dict[str, Any]],
|
||||
errors: list[dict[str, Any]],
|
||||
) -> None:
|
||||
ids = set(payloads)
|
||||
for artifact_id, payload in payloads.items():
|
||||
for field in ("id", "kind", "title", "profile"):
|
||||
if not payload.get(field):
|
||||
errors.append(
|
||||
{
|
||||
"code": "missing_profile_artifact_field",
|
||||
"profile": profile,
|
||||
"artifact_id": artifact_id,
|
||||
"field": field,
|
||||
}
|
||||
)
|
||||
if payload.get("profile") not in {profile, None}:
|
||||
errors.append(
|
||||
{
|
||||
"code": "profile_artifact_profile_mismatch",
|
||||
"profile": profile,
|
||||
"artifact_id": artifact_id,
|
||||
"value": payload.get("profile"),
|
||||
}
|
||||
)
|
||||
for relationship in payload.get("relationships") or []:
|
||||
target = relationship.get("target")
|
||||
if target and target not in ids:
|
||||
errors.append(
|
||||
{
|
||||
"code": "profile_relationship_target_not_in_payloads",
|
||||
"profile": profile,
|
||||
"artifact_id": artifact_id,
|
||||
"target": target,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _check_service_ownership(
|
||||
payloads: dict[str, dict[str, Any]],
|
||||
errors: list[dict[str, Any]],
|
||||
) -> None:
|
||||
service = _one_kind(payloads, "service")
|
||||
if not service:
|
||||
return
|
||||
owner_team = service.get("owner_team")
|
||||
if not _exists_kind(payloads, owner_team, "team"):
|
||||
errors.append(
|
||||
{
|
||||
"code": "invalid_service_owner_team",
|
||||
"artifact_id": service.get("id"),
|
||||
"owner_team": owner_team,
|
||||
}
|
||||
)
|
||||
team = payloads.get(str(owner_team))
|
||||
if team and not _exists_kind(payloads, team.get("owner_user"), "user"):
|
||||
errors.append(
|
||||
{
|
||||
"code": "invalid_team_owner_user",
|
||||
"artifact_id": team.get("id"),
|
||||
"owner_user": team.get("owner_user"),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _check_tenant_namespace_separation(
|
||||
payloads: dict[str, dict[str, Any]],
|
||||
errors: list[dict[str, Any]],
|
||||
) -> None:
|
||||
tenants = [payload for payload in payloads.values() if payload.get("kind") == "tenant"]
|
||||
namespaces = [tenant.get("namespace") for tenant in tenants]
|
||||
if len(namespaces) != len(set(namespaces)):
|
||||
errors.append({"code": "duplicate_tenant_namespace"})
|
||||
deployment = _one_kind(payloads, "deployment")
|
||||
if deployment:
|
||||
if deployment.get("namespace_strategy") != "namespace-per-tenant":
|
||||
errors.append(
|
||||
{
|
||||
"code": "invalid_namespace_strategy",
|
||||
"artifact_id": deployment.get("id"),
|
||||
"namespace_strategy": deployment.get("namespace_strategy"),
|
||||
}
|
||||
)
|
||||
tenant_namespaces = deployment.get("tenant_namespaces") or {}
|
||||
for tenant in tenants:
|
||||
if tenant.get("id") not in tenant_namespaces:
|
||||
errors.append(
|
||||
{
|
||||
"code": "tenant_missing_deployment_namespace",
|
||||
"tenant_id": tenant.get("id"),
|
||||
"deployment_id": deployment.get("id"),
|
||||
}
|
||||
)
|
||||
dataset = _one_kind(payloads, "dataset")
|
||||
if dataset:
|
||||
if dataset.get("tenant_scope") != "per-tenant":
|
||||
errors.append(
|
||||
{
|
||||
"code": "dataset_not_per_tenant",
|
||||
"artifact_id": dataset.get("id"),
|
||||
}
|
||||
)
|
||||
tenant_ids = set(dataset.get("tenant_ids") or [])
|
||||
for tenant in tenants:
|
||||
if tenant.get("id") not in tenant_ids:
|
||||
errors.append(
|
||||
{
|
||||
"code": "tenant_missing_dataset_partition",
|
||||
"tenant_id": tenant.get("id"),
|
||||
"dataset_id": dataset.get("id"),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _check_user_management_and_access(
|
||||
payloads: dict[str, dict[str, Any]],
|
||||
errors: list[dict[str, Any]],
|
||||
) -> None:
|
||||
evidence_ids = _ids_by_kind(payloads, "evidence")
|
||||
policy_ids = _ids_by_kind(payloads, "policy")
|
||||
tenant_ids = _ids_by_kind(payloads, "tenant")
|
||||
for user in [payload for payload in payloads.values() if payload.get("kind") == "user"]:
|
||||
if not user.get("teams"):
|
||||
errors.append(
|
||||
{
|
||||
"code": "user_missing_team_membership",
|
||||
"artifact_id": user.get("id"),
|
||||
}
|
||||
)
|
||||
grants = user.get("access_grants") or []
|
||||
if not grants:
|
||||
errors.append(
|
||||
{
|
||||
"code": "user_missing_access_grant",
|
||||
"artifact_id": user.get("id"),
|
||||
}
|
||||
)
|
||||
for grant in grants:
|
||||
if grant.get("tenant_id") not in tenant_ids:
|
||||
errors.append(
|
||||
{
|
||||
"code": "access_grant_missing_tenant",
|
||||
"artifact_id": user.get("id"),
|
||||
"tenant_id": grant.get("tenant_id"),
|
||||
}
|
||||
)
|
||||
if grant.get("policy_id") not in policy_ids:
|
||||
errors.append(
|
||||
{
|
||||
"code": "access_grant_missing_policy",
|
||||
"artifact_id": user.get("id"),
|
||||
"policy_id": grant.get("policy_id"),
|
||||
}
|
||||
)
|
||||
if grant.get("evidence_id") not in evidence_ids:
|
||||
errors.append(
|
||||
{
|
||||
"code": "access_grant_missing_evidence",
|
||||
"artifact_id": user.get("id"),
|
||||
"evidence_id": grant.get("evidence_id"),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _check_governance_evidence(
|
||||
payloads: dict[str, dict[str, Any]],
|
||||
errors: list[dict[str, Any]],
|
||||
) -> None:
|
||||
evidence_ids = _ids_by_kind(payloads, "evidence")
|
||||
for kind in ("policy", "control", "incident", "service", "dataset", "deployment", "task"):
|
||||
for payload in [item for item in payloads.values() if item.get("kind") == kind]:
|
||||
ids = set(payload.get("evidence_ids") or [])
|
||||
if not ids:
|
||||
errors.append(
|
||||
{
|
||||
"code": "artifact_missing_evidence",
|
||||
"artifact_id": payload.get("id"),
|
||||
"kind": kind,
|
||||
}
|
||||
)
|
||||
for evidence_id in ids:
|
||||
if evidence_id not in evidence_ids:
|
||||
errors.append(
|
||||
{
|
||||
"code": "artifact_missing_evidence_target",
|
||||
"artifact_id": payload.get("id"),
|
||||
"evidence_id": evidence_id,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _kind_counts(payloads: dict[str, dict[str, Any]]) -> dict[str, int]:
|
||||
counts: dict[str, int] = {}
|
||||
for payload in payloads.values():
|
||||
kind = str(payload.get("kind") or "unknown")
|
||||
counts[kind] = counts.get(kind, 0) + 1
|
||||
return dict(sorted(counts.items()))
|
||||
|
||||
|
||||
def _one_kind(payloads: dict[str, dict[str, Any]], kind: str) -> dict[str, Any] | None:
|
||||
for payload in payloads.values():
|
||||
if payload.get("kind") == kind:
|
||||
return payload
|
||||
return None
|
||||
|
||||
|
||||
def _exists_kind(
|
||||
payloads: dict[str, dict[str, Any]],
|
||||
artifact_id: Any,
|
||||
kind: str,
|
||||
) -> bool:
|
||||
payload = payloads.get(str(artifact_id))
|
||||
return bool(payload and payload.get("kind") == kind)
|
||||
|
||||
|
||||
def _ids_by_kind(payloads: dict[str, dict[str, Any]], kind: str) -> set[str]:
|
||||
return {
|
||||
str(payload["id"])
|
||||
for payload in payloads.values()
|
||||
if payload.get("kind") == kind and payload.get("id")
|
||||
}
|
||||
@@ -6,9 +6,8 @@ from pathlib import Path
|
||||
import json
|
||||
from typing import Any
|
||||
|
||||
import yaml
|
||||
|
||||
from . import generation
|
||||
from . import profiles
|
||||
from .bench import (
|
||||
Infospace,
|
||||
KnowledgeArtifact,
|
||||
@@ -230,15 +229,53 @@ def profile_inspect(
|
||||
f"Profile not found: {profile}",
|
||||
{"profile": profile, "path": str(profile_path)},
|
||||
)
|
||||
with profile_path.open("r", encoding="utf-8") as handle:
|
||||
data = yaml.safe_load(handle) or {}
|
||||
if not isinstance(data, dict):
|
||||
try:
|
||||
return profiles.inspect_profile(context, profile)
|
||||
except ValueError as exc:
|
||||
raise CanonServiceError(
|
||||
"invalid_profile",
|
||||
f"Profile must be a YAML mapping: {profile}",
|
||||
{"profile": profile, "path": str(profile_path)},
|
||||
) from exc
|
||||
|
||||
|
||||
def profile_validate(
|
||||
profile: str,
|
||||
root: Path | str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
context = load_context(root)
|
||||
profile_path = context.infospace_root / "profiles" / profile / "profile.yaml"
|
||||
if not profile_path.is_file():
|
||||
raise CanonServiceError(
|
||||
"missing_profile",
|
||||
f"Profile not found: {profile}",
|
||||
{"profile": profile, "path": str(profile_path)},
|
||||
)
|
||||
return {"ok": True, "profile": data, "path": str(profile_path)}
|
||||
return profiles.validate_profile(context, profile)
|
||||
|
||||
|
||||
def profile_graph(
|
||||
profile: str,
|
||||
root: Path | str | None = None,
|
||||
*,
|
||||
output_format: str = "json",
|
||||
) -> dict[str, Any]:
|
||||
context = load_context(root)
|
||||
profile_path = context.infospace_root / "profiles" / profile / "profile.yaml"
|
||||
if not profile_path.is_file():
|
||||
raise CanonServiceError(
|
||||
"missing_profile",
|
||||
f"Profile not found: {profile}",
|
||||
{"profile": profile, "path": str(profile_path)},
|
||||
)
|
||||
try:
|
||||
return profiles.profile_graph(context, profile, output_format=output_format)
|
||||
except ValueError as exc:
|
||||
raise CanonServiceError(
|
||||
"unsupported_graph_format",
|
||||
str(exc),
|
||||
{"supported": ["json", "mermaid"]},
|
||||
) from exc
|
||||
|
||||
|
||||
def generate_indexes(root: Path | str | None = None) -> dict[str, Any]:
|
||||
|
||||
@@ -39,3 +39,11 @@ def test_api_route_reads_generated_view(tmp_path) -> None:
|
||||
assert payload["ok"] is True
|
||||
assert payload["generated"] is True
|
||||
assert "# By Standard" in payload["content"]
|
||||
|
||||
|
||||
def test_api_route_validates_small_saas_profile() -> None:
|
||||
status, payload = _route("/profiles/small-saas/validate", {}, None)
|
||||
|
||||
assert status == HTTPStatus.OK
|
||||
assert payload["ok"] is True
|
||||
assert payload["details"]["artifact_count"] == 14
|
||||
|
||||
@@ -11,11 +11,11 @@ def test_cli_inspect_emits_json(capsys) -> None:
|
||||
assert exit_code == 0
|
||||
payload = json.loads(capsys.readouterr().out)
|
||||
assert payload["ok"] is True
|
||||
assert payload["infospace"]["artifact_count"] == 15
|
||||
assert payload["infospace"]["artifact_count"] == 29
|
||||
|
||||
|
||||
def test_cli_missing_profile_uses_structured_error(capsys) -> None:
|
||||
exit_code = main(["profile", "inspect", "small-saas"])
|
||||
exit_code = main(["profile", "inspect", "missing-profile"])
|
||||
|
||||
assert exit_code == 2
|
||||
payload = json.loads(capsys.readouterr().out)
|
||||
@@ -23,6 +23,15 @@ def test_cli_missing_profile_uses_structured_error(capsys) -> None:
|
||||
assert payload["error"]["code"] == "missing_profile"
|
||||
|
||||
|
||||
def test_cli_small_saas_profile_validate(capsys) -> None:
|
||||
exit_code = main(["profile", "validate", "small-saas"])
|
||||
|
||||
assert exit_code == 0
|
||||
payload = json.loads(capsys.readouterr().out)
|
||||
assert payload["ok"] is True
|
||||
assert payload["details"]["kinds"]["service"] == 1
|
||||
|
||||
|
||||
def test_cli_index_generates_views(capsys, tmp_path) -> None:
|
||||
root = tmp_path / "infospace"
|
||||
shutil.copytree(DEFAULT_INFOSPACE_ROOT, root)
|
||||
|
||||
@@ -6,6 +6,8 @@ from info_tech_canon.service import (
|
||||
inspect_canon,
|
||||
list_models,
|
||||
list_standards,
|
||||
profile_graph,
|
||||
profile_validate,
|
||||
validate_canon,
|
||||
)
|
||||
from info_tech_canon.service import DEFAULT_INFOSPACE_ROOT
|
||||
@@ -17,10 +19,12 @@ def test_inspect_canon_counts_artifact_kinds() -> None:
|
||||
|
||||
assert payload["ok"] is True
|
||||
assert payload["infospace"]["slug"] == "canon"
|
||||
assert payload["infospace"]["artifact_count"] == 15
|
||||
assert payload["infospace"]["artifact_count"] == 29
|
||||
assert payload["infospace"]["kinds"] == {
|
||||
"kernel": 2,
|
||||
"model": 11,
|
||||
"profile": 1,
|
||||
"profile-artifact": 13,
|
||||
"standard": 2,
|
||||
}
|
||||
|
||||
@@ -36,17 +40,33 @@ def test_validate_canon_passes_scaffold() -> None:
|
||||
assert payload["ok"] is True
|
||||
assert payload["errors"] == []
|
||||
assert "warnings" in payload
|
||||
assert payload["details"]["artifact_count"] == 15
|
||||
assert payload["details"]["artifact_count"] == 29
|
||||
|
||||
|
||||
def test_graph_exports_relationship_summary() -> None:
|
||||
payload = artifact_graph()
|
||||
|
||||
assert payload["ok"] is True
|
||||
assert payload["graph"]["node_count"] == 15
|
||||
assert payload["graph"]["node_count"] == 29
|
||||
assert payload["graph"]["edge_count"] > 15
|
||||
|
||||
|
||||
def test_small_saas_profile_validates() -> None:
|
||||
payload = profile_validate("small-saas")
|
||||
|
||||
assert payload["ok"] is True
|
||||
assert payload["errors"] == []
|
||||
assert payload["details"]["kinds"]["tenant"] == 2
|
||||
|
||||
|
||||
def test_small_saas_profile_graph_exports_slice() -> None:
|
||||
payload = profile_graph("small-saas")
|
||||
|
||||
assert payload["ok"] is True
|
||||
assert payload["profile"] == "small-saas"
|
||||
assert "small-saas/service/billing-portal" in payload["graph"]["nodes"]
|
||||
|
||||
|
||||
def test_generators_write_expected_assets(tmp_path) -> None:
|
||||
root = tmp_path / "infospace"
|
||||
shutil.copytree(DEFAULT_INFOSPACE_ROOT, root)
|
||||
|
||||
@@ -4,7 +4,7 @@ type: workplan
|
||||
title: "Small SaaS Profile Proof"
|
||||
domain: canon
|
||||
repo: info-tech-canon
|
||||
status: proposed
|
||||
status: finished
|
||||
priority: high
|
||||
created: "2026-05-23"
|
||||
updated: "2026-05-23"
|
||||
@@ -35,7 +35,7 @@ governance, observability, and work tracking.
|
||||
|
||||
```task
|
||||
id: ITC-WP-0004-T01
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "21801d10-2ec9-45b9-bb7a-632f251075d5"
|
||||
```
|
||||
@@ -48,7 +48,7 @@ state_hub_task_id: "21801d10-2ec9-45b9-bb7a-632f251075d5"
|
||||
|
||||
```task
|
||||
id: ITC-WP-0004-T02
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "92c860ca-174d-4d31-b11c-66750a2d3588"
|
||||
```
|
||||
@@ -62,7 +62,7 @@ state_hub_task_id: "92c860ca-174d-4d31-b11c-66750a2d3588"
|
||||
|
||||
```task
|
||||
id: ITC-WP-0004-T03
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "b342257f-beef-4ec6-b116-b9f8798df10c"
|
||||
```
|
||||
@@ -77,7 +77,7 @@ state_hub_task_id: "b342257f-beef-4ec6-b116-b9f8798df10c"
|
||||
|
||||
```task
|
||||
id: ITC-WP-0004-T04
|
||||
status: todo
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "58a85249-be34-497d-a19c-96b6b343b076"
|
||||
```
|
||||
@@ -93,3 +93,16 @@ state_hub_task_id: "58a85249-be34-497d-a19c-96b6b343b076"
|
||||
- The proof produces useful graph and JSON outputs.
|
||||
- The result is suitable as the baseline for user-engine and railiance-fabric
|
||||
evaluation.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- Added `infospace/profiles/small-saas/profile.yaml` with scope,
|
||||
assumptions, required standards, concept obligations, validation rules, and
|
||||
demo commands.
|
||||
- Added connected profile artifacts for service, system, tenants, user, team,
|
||||
dataset, deployment, task, policy, control, evidence, and incident.
|
||||
- Registered the profile and examples in `infospace/artifacts/index.yaml` so
|
||||
the graph and global validation include the proof.
|
||||
- Added `profile validate` and `profile graph` service, CLI, and API support.
|
||||
- Added a profile report and example command fixture suitable for downstream
|
||||
user-engine and railiance-fabric evaluation work.
|
||||
|
||||
@@ -56,7 +56,7 @@ workplans:
|
||||
|
||||
- id: ITC-WP-0004
|
||||
title: Small SaaS Profile Proof
|
||||
status: proposed
|
||||
status: finished
|
||||
priority: high
|
||||
path: workplans/ITC-WP-0004-small-saas-profile-proof.md
|
||||
depends_on:
|
||||
|
||||
Reference in New Issue
Block a user