domain-security 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- domain_security-0.1.0/.github/workflows/ci.yml +56 -0
- domain_security-0.1.0/.github/workflows/cleanup-guard.yml +72 -0
- domain_security-0.1.0/.github/workflows/dto-strict.yml +37 -0
- domain_security-0.1.0/.github/workflows/no-ai-attribution.yml +73 -0
- domain_security-0.1.0/.github/workflows/publish.yml +35 -0
- domain_security-0.1.0/.github/workflows/ruff.yml +29 -0
- domain_security-0.1.0/.gitignore +134 -0
- domain_security-0.1.0/CHANGELOG.md +24 -0
- domain_security-0.1.0/CODE_OF_CONDUCT.md +31 -0
- domain_security-0.1.0/CONTRIBUTING.md +70 -0
- domain_security-0.1.0/LICENSE +201 -0
- domain_security-0.1.0/PKG-INFO +306 -0
- domain_security-0.1.0/README.md +283 -0
- domain_security-0.1.0/SECURITY.md +31 -0
- domain_security-0.1.0/docs/apps/authz.md +152 -0
- domain_security-0.1.0/docs/apps/diagrams.md +147 -0
- domain_security-0.1.0/docs/apps/requires.md +149 -0
- domain_security-0.1.0/docs/apps/secrets.md +190 -0
- domain_security-0.1.0/docs/apps/security_context.md +132 -0
- domain_security-0.1.0/docs/apps/security_errors.md +256 -0
- domain_security-0.1.0/docs/apps/tenancy.md +127 -0
- domain_security-0.1.0/docs/apps/tenant_scoped.md +200 -0
- domain_security-0.1.0/docs/audits/2026-07-04-authz-security-audit.md +76 -0
- domain_security-0.1.0/docs/audits/2026-07-04-requires-security-audit.md +81 -0
- domain_security-0.1.0/docs/audits/2026-07-04-secrets-security-audit.md +96 -0
- domain_security-0.1.0/docs/audits/2026-07-04-security_context-security-audit.md +64 -0
- domain_security-0.1.0/docs/audits/2026-07-04-security_errors-security-audit.md +116 -0
- domain_security-0.1.0/docs/audits/2026-07-04-tenancy-security-audit.md +61 -0
- domain_security-0.1.0/docs/audits/2026-07-04-tenant_scoped-security-audit.md +106 -0
- domain_security-0.1.0/docs/reviews/2026-07-04-authz-review.md +70 -0
- domain_security-0.1.0/docs/reviews/2026-07-04-requires-review.md +50 -0
- domain_security-0.1.0/docs/reviews/2026-07-04-secrets-review.md +52 -0
- domain_security-0.1.0/docs/reviews/2026-07-04-security_context-review.md +54 -0
- domain_security-0.1.0/docs/reviews/2026-07-04-security_errors-review.md +50 -0
- domain_security-0.1.0/docs/reviews/2026-07-04-tenancy-review.md +51 -0
- domain_security-0.1.0/docs/reviews/2026-07-04-tenant_scoped-review.md +51 -0
- domain_security-0.1.0/domain_security/__init__.py +40 -0
- domain_security-0.1.0/domain_security/config/__init__.py +1 -0
- domain_security-0.1.0/domain_security/config/_version.py +3 -0
- domain_security-0.1.0/domain_security/conftest.py +15 -0
- domain_security-0.1.0/domain_security/context/__init__.py +1 -0
- domain_security-0.1.0/domain_security/context/constants/__init__.py +0 -0
- domain_security-0.1.0/domain_security/context/constants/security_context.py +10 -0
- domain_security-0.1.0/domain_security/context/security_context/__init__.py +11 -0
- domain_security-0.1.0/domain_security/context/security_context/security_context_client.py +51 -0
- domain_security-0.1.0/domain_security/context/security_context/security_context_objects.py +22 -0
- domain_security-0.1.0/domain_security/context/tests/__init__.py +1 -0
- domain_security-0.1.0/domain_security/context/tests/test_security_context/__init__.py +1 -0
- domain_security-0.1.0/domain_security/context/tests/test_security_context/conftest.py +39 -0
- domain_security-0.1.0/domain_security/context/tests/test_security_context/test_security_context_client.py +156 -0
- domain_security-0.1.0/domain_security/context/tests/test_security_context/test_security_context_objects.py +120 -0
- domain_security-0.1.0/domain_security/decorators/__init__.py +1 -0
- domain_security-0.1.0/domain_security/decorators/constants/__init__.py +0 -0
- domain_security-0.1.0/domain_security/decorators/constants/tenant_scoped.py +15 -0
- domain_security-0.1.0/domain_security/decorators/requires/__init__.py +5 -0
- domain_security-0.1.0/domain_security/decorators/requires/requires_client.py +54 -0
- domain_security-0.1.0/domain_security/decorators/tenant_scoped/__init__.py +8 -0
- domain_security-0.1.0/domain_security/decorators/tenant_scoped/tenant_scoped_client.py +75 -0
- domain_security-0.1.0/domain_security/decorators/tests/__init__.py +1 -0
- domain_security-0.1.0/domain_security/decorators/tests/test_requires/__init__.py +1 -0
- domain_security-0.1.0/domain_security/decorators/tests/test_requires/conftest.py +46 -0
- domain_security-0.1.0/domain_security/decorators/tests/test_requires/test_requires_client.py +202 -0
- domain_security-0.1.0/domain_security/decorators/tests/test_tenant_scoped/__init__.py +1 -0
- domain_security-0.1.0/domain_security/decorators/tests/test_tenant_scoped/conftest.py +47 -0
- domain_security-0.1.0/domain_security/decorators/tests/test_tenant_scoped/test_tenant_scoped_client.py +245 -0
- domain_security-0.1.0/domain_security/errors/__init__.py +1 -0
- domain_security-0.1.0/domain_security/errors/security_errors.py +37 -0
- domain_security-0.1.0/domain_security/errors/tests/__init__.py +1 -0
- domain_security-0.1.0/domain_security/errors/tests/test_security_errors/__init__.py +0 -0
- domain_security-0.1.0/domain_security/errors/tests/test_security_errors/conftest.py +39 -0
- domain_security-0.1.0/domain_security/errors/tests/test_security_errors/test_security_errors.py +221 -0
- domain_security-0.1.0/domain_security/py.typed +0 -0
- domain_security-0.1.0/domain_security/services/__init__.py +1 -0
- domain_security-0.1.0/domain_security/services/authz/__init__.py +6 -0
- domain_security-0.1.0/domain_security/services/authz/authz_client.py +40 -0
- domain_security-0.1.0/domain_security/services/authz/authz_objects.py +20 -0
- domain_security-0.1.0/domain_security/services/constants/__init__.py +0 -0
- domain_security-0.1.0/domain_security/services/constants/authz.py +10 -0
- domain_security-0.1.0/domain_security/services/constants/secrets.py +14 -0
- domain_security-0.1.0/domain_security/services/constants/tenancy.py +10 -0
- domain_security-0.1.0/domain_security/services/secrets/__init__.py +6 -0
- domain_security-0.1.0/domain_security/services/secrets/secrets_client.py +27 -0
- domain_security-0.1.0/domain_security/services/secrets/secrets_objects.py +29 -0
- domain_security-0.1.0/domain_security/services/tenancy/__init__.py +5 -0
- domain_security-0.1.0/domain_security/services/tenancy/tenancy_client.py +27 -0
- domain_security-0.1.0/domain_security/services/tests/__init__.py +1 -0
- domain_security-0.1.0/domain_security/services/tests/test_authz/__init__.py +1 -0
- domain_security-0.1.0/domain_security/services/tests/test_authz/conftest.py +51 -0
- domain_security-0.1.0/domain_security/services/tests/test_authz/test_authz_client.py +141 -0
- domain_security-0.1.0/domain_security/services/tests/test_authz/test_authz_objects.py +85 -0
- domain_security-0.1.0/domain_security/services/tests/test_secrets/__init__.py +1 -0
- domain_security-0.1.0/domain_security/services/tests/test_secrets/conftest.py +33 -0
- domain_security-0.1.0/domain_security/services/tests/test_secrets/test_secrets_client.py +100 -0
- domain_security-0.1.0/domain_security/services/tests/test_secrets/test_secrets_objects.py +69 -0
- domain_security-0.1.0/domain_security/services/tests/test_tenancy/__init__.py +1 -0
- domain_security-0.1.0/domain_security/services/tests/test_tenancy/conftest.py +28 -0
- domain_security-0.1.0/domain_security/services/tests/test_tenancy/test_tenancy_client.py +91 -0
- domain_security-0.1.0/pyproject.toml +92 -0
- domain_security-0.1.0/uv.lock +479 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches: [main]
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: true
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
test:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
strategy:
|
|
19
|
+
matrix:
|
|
20
|
+
python-version: ["3.11", "3.12"]
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v4
|
|
23
|
+
- uses: astral-sh/setup-uv@v4
|
|
24
|
+
with:
|
|
25
|
+
enable-cache: true
|
|
26
|
+
- name: Install Python
|
|
27
|
+
run: uv python install ${{ matrix.python-version }}
|
|
28
|
+
- name: Sync dependencies
|
|
29
|
+
run: uv sync --all-extras
|
|
30
|
+
- name: Test
|
|
31
|
+
# Collection probe: pytest exit 5 = no tests collected (skeleton stage);
|
|
32
|
+
# once the first suite lands, the full coverage-gated run applies.
|
|
33
|
+
run: |
|
|
34
|
+
set +e
|
|
35
|
+
uv run pytest --collect-only -q
|
|
36
|
+
collect=$?
|
|
37
|
+
set -e
|
|
38
|
+
if [ "$collect" -eq 5 ]; then
|
|
39
|
+
echo "No tests collected yet; skeleton stage."
|
|
40
|
+
exit 0
|
|
41
|
+
fi
|
|
42
|
+
uv run pytest -v --cov --cov-fail-under=95
|
|
43
|
+
|
|
44
|
+
mypy:
|
|
45
|
+
runs-on: ubuntu-latest
|
|
46
|
+
steps:
|
|
47
|
+
- uses: actions/checkout@v4
|
|
48
|
+
- uses: astral-sh/setup-uv@v4
|
|
49
|
+
with:
|
|
50
|
+
enable-cache: true
|
|
51
|
+
- name: Install Python 3.12
|
|
52
|
+
run: uv python install 3.12
|
|
53
|
+
- name: Sync dependencies
|
|
54
|
+
run: uv sync --all-extras
|
|
55
|
+
- name: Type-check
|
|
56
|
+
run: uv run mypy domain_security/
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
name: Cleanup Guard
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request
|
|
5
|
+
|
|
6
|
+
jobs:
|
|
7
|
+
feature-documentation:
|
|
8
|
+
name: Verify all features have audit and review docs
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
- name: Check feature documentation completeness
|
|
13
|
+
run: |
|
|
14
|
+
set -e
|
|
15
|
+
|
|
16
|
+
echo "Checking that all implemented features have audit and review documentation..."
|
|
17
|
+
|
|
18
|
+
AUDITS_DIR="docs/audits"
|
|
19
|
+
REVIEWS_DIR="docs/reviews"
|
|
20
|
+
|
|
21
|
+
FEATURES_DIRS="domain_security/context domain_security/services domain_security/decorators"
|
|
22
|
+
FEATURES=""
|
|
23
|
+
for FEATURES_DIR in $FEATURES_DIRS; do
|
|
24
|
+
if [ -d "$FEATURES_DIR" ]; then
|
|
25
|
+
FEATURES="$FEATURES $(find "$FEATURES_DIR" -maxdepth 1 -type d ! -name "__pycache__" ! -name "tests" ! -name "constants" ! -path "$FEATURES_DIR")"
|
|
26
|
+
fi
|
|
27
|
+
done
|
|
28
|
+
|
|
29
|
+
# Skeleton probe: no feature dirs yet means scaffold stage;
|
|
30
|
+
# once the first feature lands, the full doc check applies.
|
|
31
|
+
if [ -z "$FEATURES" ]; then
|
|
32
|
+
echo "No feature dirs yet; skeleton stage."
|
|
33
|
+
exit 0
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
MISSING_DOCS=0
|
|
37
|
+
|
|
38
|
+
for feature_dir in $FEATURES; do
|
|
39
|
+
feature_name=$(basename "$feature_dir")
|
|
40
|
+
|
|
41
|
+
# Skip features with no source files
|
|
42
|
+
if [ -z "$(find "$feature_dir" -maxdepth 1 -type f -name '*.py')" ]; then
|
|
43
|
+
continue
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# Skip features that are not implemented yet (docstring-only stubs, no classes or functions)
|
|
47
|
+
if ! grep -lqE '^(class |def )' "$feature_dir"/*.py 2>/dev/null; then
|
|
48
|
+
echo "SKIP: feature '$feature_name' has no implementation yet"
|
|
49
|
+
continue
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
audit_file=$(find "$AUDITS_DIR" -name "*$feature_name*audit*" 2>/dev/null | head -1)
|
|
53
|
+
review_file=$(find "$REVIEWS_DIR" -name "*$feature_name*review*" 2>/dev/null | head -1)
|
|
54
|
+
|
|
55
|
+
if [ -z "$audit_file" ]; then
|
|
56
|
+
echo "FAIL: feature '$feature_name' missing audit doc in $AUDITS_DIR"
|
|
57
|
+
MISSING_DOCS=$((MISSING_DOCS + 1))
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
if [ -z "$review_file" ]; then
|
|
61
|
+
echo "FAIL: feature '$feature_name' missing review doc in $REVIEWS_DIR"
|
|
62
|
+
MISSING_DOCS=$((MISSING_DOCS + 1))
|
|
63
|
+
fi
|
|
64
|
+
done
|
|
65
|
+
|
|
66
|
+
if [ $MISSING_DOCS -gt 0 ]; then
|
|
67
|
+
echo ""
|
|
68
|
+
echo "ERROR: $MISSING_DOCS feature(s) missing documentation."
|
|
69
|
+
exit 1
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
echo "All implemented features have corresponding audit and review docs."
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: dto-strict
|
|
2
|
+
|
|
3
|
+
# DTO-discipline lint (frozen+slots, facade-ban, R001-R006). Per-repo copy of
|
|
4
|
+
# the canonical gate; runs on the root-layout package. Empty baseline at
|
|
5
|
+
# scaffold (0 violations).
|
|
6
|
+
|
|
7
|
+
on:
|
|
8
|
+
pull_request:
|
|
9
|
+
push:
|
|
10
|
+
branches: [main]
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
permissions:
|
|
17
|
+
contents: read
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
lint:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v4
|
|
24
|
+
- uses: astral-sh/setup-uv@v4
|
|
25
|
+
with:
|
|
26
|
+
enable-cache: true
|
|
27
|
+
- name: Install Python 3.12
|
|
28
|
+
run: uv python install 3.12
|
|
29
|
+
- name: Run dto-strict
|
|
30
|
+
run: uvx --python 3.12 dto-strict@0.4.0 domain_security/ --format github
|
|
31
|
+
- name: Check LOC cap (source dirs only)
|
|
32
|
+
run: |
|
|
33
|
+
# LOC-cap step: source dirs only (test density exempt from cap per review record);
|
|
34
|
+
# grow this list as feature dirs land
|
|
35
|
+
for dir in domain_security/config domain_security/context/security_context domain_security/services/authz domain_security/services/tenancy domain_security/services/secrets domain_security/decorators/requires domain_security/decorators/tenant_scoped domain_security/errors; do
|
|
36
|
+
uvx --python 3.12 dto-strict@0.4.0 loc-cap "$dir"
|
|
37
|
+
done
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
name: Attribution Gate
|
|
2
|
+
|
|
3
|
+
# Server-side enforcement: rejects pushes/PRs whose commit messages contain
|
|
4
|
+
# Claude/Anthropic attribution. Catches GitHub squash-merge propagation that
|
|
5
|
+
# bypasses local commit-msg, pre-push, and PreToolUse hooks.
|
|
6
|
+
#
|
|
7
|
+
# Per-repo copy of the canonical attribution gate.
|
|
8
|
+
|
|
9
|
+
on:
|
|
10
|
+
push:
|
|
11
|
+
pull_request:
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
pull-requests: read
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
scan:
|
|
19
|
+
name: Scan commit messages for attribution
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- name: Checkout (full history)
|
|
23
|
+
uses: actions/checkout@v4
|
|
24
|
+
with:
|
|
25
|
+
fetch-depth: 0
|
|
26
|
+
|
|
27
|
+
- name: Determine commit range
|
|
28
|
+
id: range
|
|
29
|
+
env:
|
|
30
|
+
EVENT_NAME: ${{ github.event_name }}
|
|
31
|
+
PR_BASE: ${{ github.event.pull_request.base.sha }}
|
|
32
|
+
PR_HEAD: ${{ github.event.pull_request.head.sha }}
|
|
33
|
+
PUSH_BEFORE: ${{ github.event.before }}
|
|
34
|
+
PUSH_AFTER: ${{ github.event.after }}
|
|
35
|
+
run: |
|
|
36
|
+
set -euo pipefail
|
|
37
|
+
if [ "$EVENT_NAME" = "pull_request" ]; then
|
|
38
|
+
BASE="$PR_BASE"
|
|
39
|
+
HEAD="$PR_HEAD"
|
|
40
|
+
else
|
|
41
|
+
BASE="$PUSH_BEFORE"
|
|
42
|
+
HEAD="$PUSH_AFTER"
|
|
43
|
+
if [ "$BASE" = "0000000000000000000000000000000000000000" ] || [ -z "$BASE" ]; then
|
|
44
|
+
git fetch origin main:refs/remotes/origin/main 2>/dev/null || true
|
|
45
|
+
BASE=$(git merge-base origin/main "$HEAD" 2>/dev/null || git rev-list --max-parents=0 "$HEAD" | tail -1)
|
|
46
|
+
fi
|
|
47
|
+
fi
|
|
48
|
+
echo "base=$BASE" >> "$GITHUB_OUTPUT"
|
|
49
|
+
echo "head=$HEAD" >> "$GITHUB_OUTPUT"
|
|
50
|
+
|
|
51
|
+
- name: Scan for Claude/Anthropic attribution
|
|
52
|
+
env:
|
|
53
|
+
BASE: ${{ steps.range.outputs.base }}
|
|
54
|
+
HEAD: ${{ steps.range.outputs.head }}
|
|
55
|
+
PATTERN: 'co-authored-by.*(claude|anthropic)|generated with claude|@claude|noreply@anthropic|🤖'
|
|
56
|
+
run: |
|
|
57
|
+
set -uo pipefail
|
|
58
|
+
OFFENDING=""
|
|
59
|
+
for sha in $(git rev-list "$BASE..$HEAD"); do
|
|
60
|
+
MSG=$(git log -1 --pretty=format:"%B" "$sha")
|
|
61
|
+
if echo "$MSG" | grep -qiE "$PATTERN"; then
|
|
62
|
+
AUTHOR=$(git log -1 --pretty=format:"%an" "$sha")
|
|
63
|
+
SUBJECT=$(git log -1 --pretty=format:"%s" "$sha")
|
|
64
|
+
OFFENDING="${OFFENDING} ${sha:0:8} | author=${AUTHOR} | ${SUBJECT}"$'\n'
|
|
65
|
+
fi
|
|
66
|
+
done
|
|
67
|
+
if [ -n "$OFFENDING" ]; then
|
|
68
|
+
echo "::error::Claude/Anthropic attribution detected in commit messages"
|
|
69
|
+
echo "Offending commits in range $BASE..$HEAD:"
|
|
70
|
+
printf '%s' "$OFFENDING"
|
|
71
|
+
exit 1
|
|
72
|
+
fi
|
|
73
|
+
echo "OK: no attribution detected in $BASE..$HEAD"
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
publish:
|
|
9
|
+
name: Build + publish
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
environment: pypi # second-layer GitHub deployment-environment gate
|
|
12
|
+
permissions:
|
|
13
|
+
id-token: write # OIDC trusted publisher
|
|
14
|
+
contents: read
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- name: Checkout
|
|
18
|
+
uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Set up Python
|
|
21
|
+
uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: '3.12'
|
|
24
|
+
|
|
25
|
+
- name: Install build deps
|
|
26
|
+
run: python -m pip install --upgrade build
|
|
27
|
+
|
|
28
|
+
- name: Build sdist + wheel
|
|
29
|
+
run: python -m build
|
|
30
|
+
|
|
31
|
+
- name: Verify artifacts
|
|
32
|
+
run: python -m pip install --upgrade twine && python -m twine check dist/*
|
|
33
|
+
|
|
34
|
+
- name: Publish to PyPI
|
|
35
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Ruff
|
|
2
|
+
|
|
3
|
+
# Ruff lint + format check. Pinned to 0.15.14 to match local version.
|
|
4
|
+
# Format drift was previously undetected; this gate prevents future drift.
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
pull_request:
|
|
8
|
+
push:
|
|
9
|
+
branches: [main]
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
13
|
+
cancel-in-progress: true
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
ruff:
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v4
|
|
23
|
+
- uses: astral-sh/setup-uv@v4
|
|
24
|
+
with:
|
|
25
|
+
enable-cache: true
|
|
26
|
+
- name: Ruff lint
|
|
27
|
+
run: uvx ruff@0.15.14 check domain_security/
|
|
28
|
+
- name: Ruff format check
|
|
29
|
+
run: uvx ruff@0.15.14 format --check domain_security/
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
pip-wheel-metadata/
|
|
24
|
+
share/python-wheels/
|
|
25
|
+
*.egg-info/
|
|
26
|
+
.installed.cfg
|
|
27
|
+
*.egg
|
|
28
|
+
MANIFEST
|
|
29
|
+
|
|
30
|
+
# PyInstaller
|
|
31
|
+
*.manifest
|
|
32
|
+
*.spec
|
|
33
|
+
|
|
34
|
+
# Installer logs
|
|
35
|
+
pip-log.txt
|
|
36
|
+
pip-delete-this-directory.txt
|
|
37
|
+
|
|
38
|
+
# Unit test / coverage reports
|
|
39
|
+
htmlcov/
|
|
40
|
+
.tox/
|
|
41
|
+
.nox/
|
|
42
|
+
.coverage
|
|
43
|
+
.coverage.*
|
|
44
|
+
.cache
|
|
45
|
+
nosetests.xml
|
|
46
|
+
coverage.xml
|
|
47
|
+
*.cover
|
|
48
|
+
*.py,cover
|
|
49
|
+
.hypothesis/
|
|
50
|
+
.pytest_cache/
|
|
51
|
+
|
|
52
|
+
# Translations
|
|
53
|
+
*.mo
|
|
54
|
+
*.pot
|
|
55
|
+
|
|
56
|
+
# Django stuff:
|
|
57
|
+
*.log
|
|
58
|
+
local_settings.py
|
|
59
|
+
db.sqlite3
|
|
60
|
+
db.sqlite3-journal
|
|
61
|
+
|
|
62
|
+
# Flask stuff:
|
|
63
|
+
instance/
|
|
64
|
+
.webassets-cache
|
|
65
|
+
|
|
66
|
+
# Scrapy stuff:
|
|
67
|
+
.scrapy
|
|
68
|
+
|
|
69
|
+
# Sphinx documentation
|
|
70
|
+
docs/_build/
|
|
71
|
+
|
|
72
|
+
# PyBuilder
|
|
73
|
+
target/
|
|
74
|
+
|
|
75
|
+
# Jupyter Notebook
|
|
76
|
+
.ipynb_checkpoints
|
|
77
|
+
|
|
78
|
+
# IPython
|
|
79
|
+
profile_default/
|
|
80
|
+
ipython_config.py
|
|
81
|
+
|
|
82
|
+
# pyenv
|
|
83
|
+
.python-version
|
|
84
|
+
|
|
85
|
+
# pipenv
|
|
86
|
+
Pipfile.lock
|
|
87
|
+
|
|
88
|
+
# PEP 582
|
|
89
|
+
__pypackages__/
|
|
90
|
+
|
|
91
|
+
# Celery stuff
|
|
92
|
+
celerybeat-schedule
|
|
93
|
+
celerybeat.pid
|
|
94
|
+
|
|
95
|
+
# SageMath parsed files
|
|
96
|
+
*.sage.py
|
|
97
|
+
|
|
98
|
+
# Environments
|
|
99
|
+
.env
|
|
100
|
+
.venv
|
|
101
|
+
env/
|
|
102
|
+
venv/
|
|
103
|
+
ENV/
|
|
104
|
+
env.bak/
|
|
105
|
+
venv.bak/
|
|
106
|
+
|
|
107
|
+
# Spyder project settings
|
|
108
|
+
.spyderproject
|
|
109
|
+
.spyproject
|
|
110
|
+
|
|
111
|
+
# Rope project settings
|
|
112
|
+
.ropeproject
|
|
113
|
+
|
|
114
|
+
# mkdocs documentation
|
|
115
|
+
/site
|
|
116
|
+
|
|
117
|
+
# mypy
|
|
118
|
+
.mypy_cache/
|
|
119
|
+
.dmypy.json
|
|
120
|
+
dmypy.json
|
|
121
|
+
|
|
122
|
+
# Pyre type checker
|
|
123
|
+
.pyre/
|
|
124
|
+
|
|
125
|
+
# IDE
|
|
126
|
+
.vscode/
|
|
127
|
+
.idea/
|
|
128
|
+
*.swp
|
|
129
|
+
*.swo
|
|
130
|
+
*~
|
|
131
|
+
|
|
132
|
+
# uv
|
|
133
|
+
.venv
|
|
134
|
+
.venv.lock
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0] - 2026-07-04
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- SecurityContext and Principal frozen dataclasses for ambient identity and tenant boundaries
|
|
15
|
+
- SecurityContextManager for set/get/bind/clear of ambient context via ContextVar
|
|
16
|
+
- Authorizer class with check() and require() for scope-based permission enforcement
|
|
17
|
+
- Permission and PolicyDecision value objects for authorization decisions
|
|
18
|
+
- TenancyGuard for tenant-boundary enforcement
|
|
19
|
+
- @requires decorator for declarative permission checks on methods
|
|
20
|
+
- @tenant_scoped decorator for declarative tenant-boundary enforcement
|
|
21
|
+
- SecretRef and SecretValue for lazy, masked secret resolution
|
|
22
|
+
- SecretsBackend Protocol for pluggable secret fetching
|
|
23
|
+
- SecurityError base exception with subclasses AuthzError, TenancyError, SecretError
|
|
24
|
+
- All errors integrate with domain-errors for structured logging and HTTP status codes
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Code of Conduct
|
|
2
|
+
|
|
3
|
+
## My Commitment
|
|
4
|
+
|
|
5
|
+
I maintain this project solo, and I am committed to keeping it a welcoming space for everyone who participates in issues, pull requests, and discussions. I pledge to treat every participant with respect and dignity, regardless of age, body size, caste, disability, ethnicity, sex characteristics, gender, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, sexual identity and orientation, or any other dimension of diversity.
|
|
6
|
+
|
|
7
|
+
## Standards
|
|
8
|
+
|
|
9
|
+
Behavior that keeps this a positive space:
|
|
10
|
+
|
|
11
|
+
- Welcoming and inclusive language
|
|
12
|
+
- Respect for differing viewpoints and experiences
|
|
13
|
+
- Gracefully accepting constructive criticism
|
|
14
|
+
- Focusing on what is best for the project
|
|
15
|
+
- Empathy toward other participants
|
|
16
|
+
|
|
17
|
+
Behavior I will not accept:
|
|
18
|
+
|
|
19
|
+
- Harassment or insulting or derogatory comments
|
|
20
|
+
- Personal attacks
|
|
21
|
+
- Public or private harassment
|
|
22
|
+
- Publishing someone's private information without consent
|
|
23
|
+
- Conduct that could reasonably be considered inappropriate
|
|
24
|
+
|
|
25
|
+
## Enforcement
|
|
26
|
+
|
|
27
|
+
Report unacceptable behavior to me through GitHub, either by opening an issue or, where discretion is warranted, through private vulnerability reporting. I review and act on every report promptly and fairly, and I respect the privacy and security of anyone who reports.
|
|
28
|
+
|
|
29
|
+
## Attribution
|
|
30
|
+
|
|
31
|
+
This Code of Conduct is adapted from the Contributor Covenant, version 2.1, available at https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in contributing to domain-security. This guide explains how to set up your development environment, run tests and linters, and follow our code standards.
|
|
4
|
+
|
|
5
|
+
## Development Setup
|
|
6
|
+
|
|
7
|
+
This project uses **uv** for dependency management. Install it first, then sync dependencies:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
uv sync
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
This creates a virtual environment and installs all development dependencies, including testing, linting, type-checking, and formatting tools.
|
|
14
|
+
|
|
15
|
+
## Running Checks
|
|
16
|
+
|
|
17
|
+
All checks must pass before code is merged:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Run tests
|
|
21
|
+
uv run pytest
|
|
22
|
+
|
|
23
|
+
# Check code style and imports
|
|
24
|
+
uv run ruff check
|
|
25
|
+
|
|
26
|
+
# Format code
|
|
27
|
+
uv run ruff format
|
|
28
|
+
|
|
29
|
+
# Type check (mypy)
|
|
30
|
+
uv run mypy
|
|
31
|
+
|
|
32
|
+
# Type check (pyright alternative)
|
|
33
|
+
uv run pyright
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Run these locally before opening a pull request to catch issues early.
|
|
37
|
+
|
|
38
|
+
## Code Style
|
|
39
|
+
|
|
40
|
+
This project follows these conventions:
|
|
41
|
+
|
|
42
|
+
- **Dataclasses**: Use `@dataclass(frozen=True, slots=True)` for immutable value types.
|
|
43
|
+
- **Docstrings**: One-line docstrings for modules, classes, and functions. Use triple quotes even for single lines.
|
|
44
|
+
- **Imports**: Import abstract base classes from `collections.abc` (not `typing`). Use absolute imports (no relative imports).
|
|
45
|
+
- **Methods**: Every method lives in a class or container: no module-level functions. Containers keep methods organized.
|
|
46
|
+
- **Constants**: Extract magic constants to `constants/` directory only when they are semantically significant (shared across modules or define behavior).
|
|
47
|
+
|
|
48
|
+
## Pull Request Flow
|
|
49
|
+
|
|
50
|
+
1. **Branch**: Create a feature branch off `main` (e.g., `git checkout -b feature/my-feature`).
|
|
51
|
+
2. **Commit**: Make small, clear commits. Each commit author is the person who wrote the code, with no co-author or AI attribution trailers.
|
|
52
|
+
3. **Push**: Push your branch and open a pull request on GitHub.
|
|
53
|
+
4. **Review**: The maintainer will review your code, request changes if needed, and merge when ready. Contributors do not merge their own PRs.
|
|
54
|
+
|
|
55
|
+
## Commit Messages
|
|
56
|
+
|
|
57
|
+
Write clear, descriptive commit messages that explain *why* the change was made. Example:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
Add @wrap_errors decorator for automatic error domain wrapping
|
|
61
|
+
|
|
62
|
+
Simplifies error handling across services by applying domain
|
|
63
|
+
classification to function arguments without try/except boilerplate.
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Do not include co-author or AI attribution trailers in commit messages.
|
|
67
|
+
|
|
68
|
+
## Community Standards
|
|
69
|
+
|
|
70
|
+
Please read [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) before participating. We expect respectful collaboration and inclusive language in all interactions.
|