openbox-langgraph-sdk-python 0.1.2__tar.gz → 1.0.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.
Files changed (157) hide show
  1. openbox_langgraph_sdk_python-1.0.0/.coverage +0 -0
  2. openbox_langgraph_sdk_python-1.0.0/.github/CODEOWNERS +10 -0
  3. openbox_langgraph_sdk_python-1.0.0/.github/workflows/pr-governance.yml +128 -0
  4. openbox_langgraph_sdk_python-1.0.0/.github/workflows/pr-quality.yml +204 -0
  5. openbox_langgraph_sdk_python-1.0.0/.github/workflows/pr-security.yml +173 -0
  6. openbox_langgraph_sdk_python-1.0.0/.github/workflows/publish.yml +433 -0
  7. {openbox_langgraph_sdk_python-0.1.2 → openbox_langgraph_sdk_python-1.0.0}/.gitignore +4 -0
  8. openbox_langgraph_sdk_python-1.0.0/.gitleaks.toml +2 -0
  9. openbox_langgraph_sdk_python-1.0.0/CHANGELOG.md +60 -0
  10. {openbox_langgraph_sdk_python-0.1.2 → openbox_langgraph_sdk_python-1.0.0}/CLAUDE.md +4 -2
  11. openbox_langgraph_sdk_python-1.0.0/CODE_OF_CONDUCT.md +128 -0
  12. openbox_langgraph_sdk_python-1.0.0/LICENSE +21 -0
  13. {openbox_langgraph_sdk_python-0.1.2 → openbox_langgraph_sdk_python-1.0.0}/PKG-INFO +21 -9
  14. {openbox_langgraph_sdk_python-0.1.2 → openbox_langgraph_sdk_python-1.0.0}/README.md +14 -7
  15. openbox_langgraph_sdk_python-1.0.0/SECURITY.md +27 -0
  16. openbox_langgraph_sdk_python-1.0.0/coverage.xml +2078 -0
  17. openbox_langgraph_sdk_python-1.0.0/demo/demo_04_content_builder_langgraph/.env.example +11 -0
  18. openbox_langgraph_sdk_python-1.0.0/demo/demo_04_content_builder_langgraph/.gitignore +5 -0
  19. openbox_langgraph_sdk_python-1.0.0/demo/demo_04_content_builder_langgraph/AGENTS.md +43 -0
  20. openbox_langgraph_sdk_python-1.0.0/demo/demo_04_content_builder_langgraph/README.md +68 -0
  21. openbox_langgraph_sdk_python-1.0.0/demo/demo_04_content_builder_langgraph/pyproject.toml +31 -0
  22. openbox_langgraph_sdk_python-1.0.0/demo/demo_04_content_builder_langgraph/skills/blog-post/SKILL.md +126 -0
  23. openbox_langgraph_sdk_python-1.0.0/demo/demo_04_content_builder_langgraph/skills/social-media/SKILL.md +177 -0
  24. openbox_langgraph_sdk_python-1.0.0/demo/demo_04_content_builder_langgraph/src/demo_04_content_builder_langgraph/__init__.py +1 -0
  25. openbox_langgraph_sdk_python-1.0.0/demo/demo_04_content_builder_langgraph/src/demo_04_content_builder_langgraph/agent.py +74 -0
  26. openbox_langgraph_sdk_python-1.0.0/demo/demo_04_content_builder_langgraph/src/demo_04_content_builder_langgraph/main.py +101 -0
  27. openbox_langgraph_sdk_python-1.0.0/demo/demo_04_content_builder_langgraph/src/demo_04_content_builder_langgraph/paths.py +10 -0
  28. openbox_langgraph_sdk_python-1.0.0/demo/demo_04_content_builder_langgraph/src/demo_04_content_builder_langgraph/prompt.py +77 -0
  29. openbox_langgraph_sdk_python-1.0.0/demo/demo_04_content_builder_langgraph/src/demo_04_content_builder_langgraph/tools_content.py +84 -0
  30. openbox_langgraph_sdk_python-1.0.0/demo/demo_04_content_builder_langgraph/src/demo_04_content_builder_langgraph/tools_fs.py +63 -0
  31. openbox_langgraph_sdk_python-1.0.0/demo/demo_04_content_builder_langgraph/uv.lock +2130 -0
  32. {openbox_langgraph_sdk_python-0.1.2 → openbox_langgraph_sdk_python-1.0.0}/openbox_langgraph/__init__.py +17 -0
  33. openbox_langgraph_sdk_python-1.0.0/openbox_langgraph/activity_context_binding.py +126 -0
  34. openbox_langgraph_sdk_python-1.0.0/openbox_langgraph/client.py +549 -0
  35. {openbox_langgraph_sdk_python-0.1.2 → openbox_langgraph_sdk_python-1.0.0}/openbox_langgraph/config.py +101 -13
  36. openbox_langgraph_sdk_python-1.0.0/openbox_langgraph/core_adapter.py +223 -0
  37. openbox_langgraph_sdk_python-1.0.0/openbox_langgraph/core_events.py +141 -0
  38. openbox_langgraph_sdk_python-1.0.0/openbox_langgraph/core_runtime.py +169 -0
  39. {openbox_langgraph_sdk_python-0.1.2 → openbox_langgraph_sdk_python-1.0.0}/openbox_langgraph/errors.py +4 -0
  40. openbox_langgraph_sdk_python-1.0.0/openbox_langgraph/identity.py +170 -0
  41. {openbox_langgraph_sdk_python-0.1.2 → openbox_langgraph_sdk_python-1.0.0}/openbox_langgraph/langgraph_handler.py +835 -300
  42. openbox_langgraph_sdk_python-1.0.0/openbox_langgraph/langgraph_hook_runtime.py +201 -0
  43. openbox_langgraph_sdk_python-1.0.0/openbox_langgraph/otel_setup.py +36 -0
  44. {openbox_langgraph_sdk_python-0.1.2 → openbox_langgraph_sdk_python-1.0.0}/openbox_langgraph/span_processor.py +18 -6
  45. openbox_langgraph_sdk_python-1.0.0/openbox_langgraph/tool_activity_binding.py +339 -0
  46. openbox_langgraph_sdk_python-1.0.0/openbox_langgraph/trace_context_registry.py +197 -0
  47. {openbox_langgraph_sdk_python-0.1.2 → openbox_langgraph_sdk_python-1.0.0}/openbox_langgraph/tracing.py +7 -127
  48. {openbox_langgraph_sdk_python-0.1.2 → openbox_langgraph_sdk_python-1.0.0}/openbox_langgraph/types.py +168 -9
  49. {openbox_langgraph_sdk_python-0.1.2 → openbox_langgraph_sdk_python-1.0.0}/pyproject.toml +31 -2
  50. openbox_langgraph_sdk_python-1.0.0/sonar-project.properties +14 -0
  51. openbox_langgraph_sdk_python-1.0.0/tests/conftest.py +69 -0
  52. openbox_langgraph_sdk_python-1.0.0/tests/golden/README.md +171 -0
  53. openbox_langgraph_sdk_python-1.0.0/tests/golden/__init__.py +6 -0
  54. openbox_langgraph_sdk_python-1.0.0/tests/golden/capture_harness.py +177 -0
  55. openbox_langgraph_sdk_python-1.0.0/tests/golden/chain_completed.normalized.json +60 -0
  56. openbox_langgraph_sdk_python-1.0.0/tests/golden/chain_completed.raw.json +60 -0
  57. openbox_langgraph_sdk_python-1.0.0/tests/golden/chain_started.handbuilt_serialization_pin.normalized.json +17 -0
  58. openbox_langgraph_sdk_python-1.0.0/tests/golden/chain_started.handbuilt_serialization_pin.raw.json +17 -0
  59. openbox_langgraph_sdk_python-1.0.0/tests/golden/fake_agent_graphs.py +125 -0
  60. openbox_langgraph_sdk_python-1.0.0/tests/golden/generate_fixtures.py +135 -0
  61. openbox_langgraph_sdk_python-1.0.0/tests/golden/graph_capture_harness.py +196 -0
  62. openbox_langgraph_sdk_python-1.0.0/tests/golden/headers_signed.normalized.json +34 -0
  63. openbox_langgraph_sdk_python-1.0.0/tests/golden/headers_signed.raw.json +34 -0
  64. openbox_langgraph_sdk_python-1.0.0/tests/golden/headers_unsigned.normalized.json +24 -0
  65. openbox_langgraph_sdk_python-1.0.0/tests/golden/headers_unsigned.raw.json +24 -0
  66. openbox_langgraph_sdk_python-1.0.0/tests/golden/id_normalization.py +135 -0
  67. openbox_langgraph_sdk_python-1.0.0/tests/golden/layer1_handbuilt_pins.py +71 -0
  68. openbox_langgraph_sdk_python-1.0.0/tests/golden/llm_completed.normalized.json +29 -0
  69. openbox_langgraph_sdk_python-1.0.0/tests/golden/llm_completed.raw.json +29 -0
  70. openbox_langgraph_sdk_python-1.0.0/tests/golden/llm_started.normalized.json +18 -0
  71. openbox_langgraph_sdk_python-1.0.0/tests/golden/llm_started.raw.json +18 -0
  72. openbox_langgraph_sdk_python-1.0.0/tests/golden/ordering_single_llm_turn.json +22 -0
  73. openbox_langgraph_sdk_python-1.0.0/tests/golden/ordering_tool_call_turn.json +38 -0
  74. openbox_langgraph_sdk_python-1.0.0/tests/golden/ordering_two_llm_calls_turn.json +30 -0
  75. openbox_langgraph_sdk_python-1.0.0/tests/golden/real_emitted_event_fixtures.py +136 -0
  76. openbox_langgraph_sdk_python-1.0.0/tests/golden/signal_received.normalized.json +16 -0
  77. openbox_langgraph_sdk_python-1.0.0/tests/golden/signal_received.raw.json +16 -0
  78. openbox_langgraph_sdk_python-1.0.0/tests/golden/subagent_tool_completed.normalized.json +30 -0
  79. openbox_langgraph_sdk_python-1.0.0/tests/golden/subagent_tool_completed.raw.json +30 -0
  80. openbox_langgraph_sdk_python-1.0.0/tests/golden/subagent_tool_started.normalized.json +31 -0
  81. openbox_langgraph_sdk_python-1.0.0/tests/golden/subagent_tool_started.raw.json +31 -0
  82. openbox_langgraph_sdk_python-1.0.0/tests/golden/tool_completed.normalized.json +28 -0
  83. openbox_langgraph_sdk_python-1.0.0/tests/golden/tool_completed.raw.json +28 -0
  84. openbox_langgraph_sdk_python-1.0.0/tests/golden/tool_started.normalized.json +23 -0
  85. openbox_langgraph_sdk_python-1.0.0/tests/golden/tool_started.raw.json +23 -0
  86. openbox_langgraph_sdk_python-1.0.0/tests/golden/workflow_completed_error_close.normalized.json +14 -0
  87. openbox_langgraph_sdk_python-1.0.0/tests/golden/workflow_completed_error_close.raw.json +14 -0
  88. openbox_langgraph_sdk_python-1.0.0/tests/golden/workflow_failed.handbuilt_serialization_pin.normalized.json +16 -0
  89. openbox_langgraph_sdk_python-1.0.0/tests/golden/workflow_failed.handbuilt_serialization_pin.raw.json +16 -0
  90. openbox_langgraph_sdk_python-1.0.0/tests/golden/workflow_started.normalized.json +26 -0
  91. openbox_langgraph_sdk_python-1.0.0/tests/golden/workflow_started.raw.json +26 -0
  92. openbox_langgraph_sdk_python-1.0.0/tests/test_activity_context_binding.py +688 -0
  93. openbox_langgraph_sdk_python-1.0.0/tests/test_agent_identity.py +94 -0
  94. openbox_langgraph_sdk_python-1.0.0/tests/test_approval_strict_parsing.py +76 -0
  95. openbox_langgraph_sdk_python-1.0.0/tests/test_client_shim_compat.py +99 -0
  96. openbox_langgraph_sdk_python-1.0.0/tests/test_config_client_core.py +257 -0
  97. openbox_langgraph_sdk_python-1.0.0/tests/test_config_resolution_precedence.py +29 -0
  98. openbox_langgraph_sdk_python-1.0.0/tests/test_context_cleanup_on_error.py +341 -0
  99. openbox_langgraph_sdk_python-1.0.0/tests/test_context_fallback_task_and_thread.py +194 -0
  100. openbox_langgraph_sdk_python-1.0.0/tests/test_context_turn_isolation.py +315 -0
  101. openbox_langgraph_sdk_python-1.0.0/tests/test_core_conformance_suite.py +173 -0
  102. openbox_langgraph_sdk_python-1.0.0/tests/test_core_context_binding.py +350 -0
  103. openbox_langgraph_sdk_python-1.0.0/tests/test_core_events_envelopes.py +299 -0
  104. openbox_langgraph_sdk_python-1.0.0/tests/test_core_runtime_config.py +126 -0
  105. openbox_langgraph_sdk_python-1.0.0/tests/test_did_client_signing.py +120 -0
  106. openbox_langgraph_sdk_python-1.0.0/tests/test_fail_open_block_preserved.py +113 -0
  107. openbox_langgraph_sdk_python-1.0.0/tests/test_framework_adapter_translation.py +233 -0
  108. openbox_langgraph_sdk_python-1.0.0/tests/test_gate_error_translation.py +104 -0
  109. openbox_langgraph_sdk_python-1.0.0/tests/test_golden_baseline.py +214 -0
  110. openbox_langgraph_sdk_python-1.0.0/tests/test_governance_changes.py +158 -0
  111. openbox_langgraph_sdk_python-1.0.0/tests/test_halt_run_isolation.py +157 -0
  112. openbox_langgraph_sdk_python-1.0.0/tests/test_hook_approval_retry.py +242 -0
  113. openbox_langgraph_sdk_python-1.0.0/tests/test_hook_context_pinning.py +128 -0
  114. openbox_langgraph_sdk_python-1.0.0/tests/test_hook_family_exclusivity.py +207 -0
  115. openbox_langgraph_sdk_python-1.0.0/tests/test_langchain_callback_dedup.py +522 -0
  116. openbox_langgraph_sdk_python-1.0.0/tests/test_langchain_callback_llm_context.py +531 -0
  117. openbox_langgraph_sdk_python-1.0.0/tests/test_langchain_callback_tool_ordering.py +391 -0
  118. openbox_langgraph_sdk_python-1.0.0/tests/test_lifecycle_golden_parity.py +158 -0
  119. openbox_langgraph_sdk_python-1.0.0/tests/test_loop_liveness_on_sync_approval.py +131 -0
  120. openbox_langgraph_sdk_python-1.0.0/tests/test_public_exports_baseline.py +115 -0
  121. openbox_langgraph_sdk_python-1.0.0/tests/test_recording_client_seam.py +64 -0
  122. openbox_langgraph_sdk_python-1.0.0/tests/test_signed_headers_parity.py +74 -0
  123. openbox_langgraph_sdk_python-1.0.0/tests/test_types_hook_core.py +98 -0
  124. openbox_langgraph_sdk_python-1.0.0/tests/test_verdict_span_hitl_core.py +238 -0
  125. openbox_langgraph_sdk_python-1.0.0/tests/test_version_static.py +53 -0
  126. {openbox_langgraph_sdk_python-0.1.2 → openbox_langgraph_sdk_python-1.0.0}/uv.lock +503 -65
  127. openbox_langgraph_sdk_python-0.1.2/.github/workflows/publish.yml +0 -71
  128. openbox_langgraph_sdk_python-0.1.2/openbox_langgraph/client.py +0 -358
  129. openbox_langgraph_sdk_python-0.1.2/openbox_langgraph/db_governance_hooks.py +0 -897
  130. openbox_langgraph_sdk_python-0.1.2/openbox_langgraph/file_governance_hooks.py +0 -419
  131. openbox_langgraph_sdk_python-0.1.2/openbox_langgraph/hook_governance.py +0 -397
  132. openbox_langgraph_sdk_python-0.1.2/openbox_langgraph/http_governance_hooks.py +0 -723
  133. openbox_langgraph_sdk_python-0.1.2/openbox_langgraph/otel_setup.py +0 -468
  134. openbox_langgraph_sdk_python-0.1.2/plans/260320-0329-remove-span-collector/plan.md +0 -121
  135. openbox_langgraph_sdk_python-0.1.2/plans/260321-2019-port-deepagent-fixes/phase-01-remove-hitl-gates.md +0 -53
  136. openbox_langgraph_sdk_python-0.1.2/plans/260321-2019-port-deepagent-fixes/phase-02-sqlalchemy-engine.md +0 -46
  137. openbox_langgraph_sdk_python-0.1.2/plans/260321-2019-port-deepagent-fixes/phase-03-hook-hitl-retry.md +0 -80
  138. openbox_langgraph_sdk_python-0.1.2/plans/260321-2019-port-deepagent-fixes/plan.md +0 -42
  139. openbox_langgraph_sdk_python-0.1.2/plans/reports/Explore-260330-1430-comprehensive-sdk-analysis.md +0 -1753
  140. openbox_langgraph_sdk_python-0.1.2/plans/reports/Explore-260330-2300-file-reference.md +0 -215
  141. openbox_langgraph_sdk_python-0.1.2/plans/reports/Explore-260330-2300-integration-guide.md +0 -747
  142. openbox_langgraph_sdk_python-0.1.2/plans/reports/code-reviewer-260323-1101-code-reuse-otel-hooks.md +0 -206
  143. openbox_langgraph_sdk_python-0.1.2/plans/reports/code-reviewer-260323-1101-efficiency-review-otel-http-hook-spans.md +0 -193
  144. openbox_langgraph_sdk_python-0.1.2/plans/reports/code-reviewer-260323-1101-hacky-patterns-review.md +0 -175
  145. openbox_langgraph_sdk_python-0.1.2/plans/reports/docs-manager-260321-2153-initial-documentation.md +0 -363
  146. openbox_langgraph_sdk_python-0.1.2/plans/reports/span-flow-visualization.html +0 -456
  147. openbox_langgraph_sdk_python-0.1.2/tests/test_governance_changes.py +0 -279
  148. openbox_langgraph_sdk_python-0.1.2/tests/test_telemetry_payload.py +0 -333
  149. {openbox_langgraph_sdk_python-0.1.2 → openbox_langgraph_sdk_python-1.0.0}/AGENTS.md +0 -0
  150. {openbox_langgraph_sdk_python-0.1.2 → openbox_langgraph_sdk_python-1.0.0}/docs/code-standards.md +0 -0
  151. {openbox_langgraph_sdk_python-0.1.2 → openbox_langgraph_sdk_python-1.0.0}/docs/codebase-summary.md +0 -0
  152. {openbox_langgraph_sdk_python-0.1.2 → openbox_langgraph_sdk_python-1.0.0}/docs/project-overview-pdr.md +0 -0
  153. {openbox_langgraph_sdk_python-0.1.2 → openbox_langgraph_sdk_python-1.0.0}/docs/project-roadmap.md +0 -0
  154. {openbox_langgraph_sdk_python-0.1.2 → openbox_langgraph_sdk_python-1.0.0}/docs/system-architecture.md +0 -0
  155. {openbox_langgraph_sdk_python-0.1.2 → openbox_langgraph_sdk_python-1.0.0}/openbox_langgraph/hitl.py +0 -0
  156. {openbox_langgraph_sdk_python-0.1.2 → openbox_langgraph_sdk_python-1.0.0}/openbox_langgraph/verdict_handler.py +0 -0
  157. {openbox_langgraph_sdk_python-0.1.2 → openbox_langgraph_sdk_python-1.0.0}/tests/test_contextvars_propagation.py +0 -0
@@ -0,0 +1,10 @@
1
+ # Default owner
2
+ * @datle-krnl
3
+
4
+ # Governance and release controls
5
+ /.github/workflows/ @datle-krnl
6
+ /.github/CODEOWNERS @datle-krnl
7
+ /.gitleaks.toml @datle-krnl
8
+ /SECURITY.md @datle-krnl
9
+ /LICENSE @datle-krnl
10
+ /pyproject.toml @datle-krnl
@@ -0,0 +1,128 @@
1
+ name: PR Governance
2
+
3
+ on:
4
+ pull_request:
5
+ branches:
6
+ - main
7
+ types:
8
+ - opened
9
+ - reopened
10
+ - synchronize
11
+ - edited
12
+ - ready_for_review
13
+ push:
14
+ branches:
15
+ - main
16
+ workflow_dispatch:
17
+
18
+ permissions:
19
+ contents: read
20
+ pull-requests: read
21
+
22
+ concurrency:
23
+ group: pr-governance-${{ github.event.pull_request.number || github.ref }}
24
+ cancel-in-progress: true
25
+
26
+ jobs:
27
+ governance:
28
+ name: Validate PR governance
29
+ runs-on: ubuntu-latest
30
+
31
+ steps:
32
+ - name: Checkout repository
33
+ uses: actions/checkout@v4
34
+ with:
35
+ fetch-depth: 0
36
+
37
+ - name: Validate branch naming
38
+ if: github.event_name == 'pull_request'
39
+ env:
40
+ BRANCH_NAME: ${{ github.head_ref }}
41
+ run: |
42
+ pattern='^(feat|fix|hotfix|chore|docs|refactor|test|ci|build|release)\/[a-z0-9._-]+$'
43
+ if [[ ! "${BRANCH_NAME}" =~ ${pattern} ]]; then
44
+ echo "Invalid branch name: ${BRANCH_NAME}"
45
+ echo "Expected pattern: <type>/<short-description>"
46
+ exit 1
47
+ fi
48
+
49
+ - name: Validate PR title convention
50
+ if: github.event_name == 'pull_request'
51
+ env:
52
+ PR_TITLE: ${{ github.event.pull_request.title }}
53
+ run: |
54
+ pattern='^(feat|fix|chore|docs|refactor|test|build|ci|perf|revert)(\([a-z0-9._/-]+\))?!?: .+$'
55
+ if [[ ! "${PR_TITLE}" =~ ${pattern} ]]; then
56
+ echo "Invalid PR title: ${PR_TITLE}"
57
+ echo "Use Conventional Commits, for example: feat(worker): add hook governance"
58
+ exit 1
59
+ fi
60
+
61
+ - name: Validate commit messages when enabled
62
+ if: github.event_name == 'pull_request' && vars.ENFORCE_COMMIT_CONVENTION == 'true'
63
+ env:
64
+ BASE_REF: ${{ github.event.pull_request.base.ref }}
65
+ run: |
66
+ git fetch origin "${BASE_REF}" --depth=1
67
+ invalid=0
68
+ while IFS= read -r subject; do
69
+ if [[ -z "${subject}" ]]; then
70
+ continue
71
+ fi
72
+ if [[ "${subject}" =~ ^Merge\ ]]; then
73
+ continue
74
+ fi
75
+ if [[ ! "${subject}" =~ ^(feat|fix|chore|docs|refactor|test|build|ci|perf|revert)(\([a-z0-9._/-]+\))?!?:\ .+ ]]; then
76
+ echo "Invalid commit subject: ${subject}"
77
+ invalid=1
78
+ fi
79
+ done < <(git log --format=%s "origin/${BASE_REF}..HEAD")
80
+ exit "${invalid}"
81
+
82
+ - name: Validate sensitive path ownership policy
83
+ if: github.event_name == 'pull_request'
84
+ env:
85
+ BASE_REF: ${{ github.event.pull_request.base.ref }}
86
+ run: |
87
+ git fetch origin "${BASE_REF}" --depth=1
88
+ mapfile -t changed_files < <(git diff --name-only "origin/${BASE_REF}...HEAD")
89
+
90
+ if [ ! -f .github/CODEOWNERS ]; then
91
+ echo ".github/CODEOWNERS is required"
92
+ exit 1
93
+ fi
94
+
95
+ needs_check=0
96
+ for file in "${changed_files[@]}"; do
97
+ case "${file}" in
98
+ .github/workflows/*|.github/CODEOWNERS|SECURITY.md|.gitleaks.toml)
99
+ needs_check=1
100
+ ;;
101
+ esac
102
+ done
103
+
104
+ if [ "${needs_check}" -eq 0 ]; then
105
+ exit 0
106
+ fi
107
+
108
+ declare -A required_entries=(
109
+ ["/.github/workflows/"]="workflow owners"
110
+ ["/.github/CODEOWNERS"]="codeowners owners"
111
+ ["/SECURITY.md"]="security owners"
112
+ ["/.gitleaks.toml"]="secret scanning owners"
113
+ )
114
+
115
+ missing=()
116
+ for pattern in "${!required_entries[@]}"; do
117
+ if ! awk '!/^#/ && NF >= 2 {print $1}' .github/CODEOWNERS | grep -Fxq "${pattern}"; then
118
+ missing+=("${required_entries[$pattern]} (${pattern})")
119
+ fi
120
+ done
121
+
122
+ if [ "${#missing[@]}" -gt 0 ]; then
123
+ printf 'Missing CODEOWNERS coverage for:\n'
124
+ printf ' - %s\n' "${missing[@]}"
125
+ exit 1
126
+ fi
127
+
128
+ echo "Sensitive file ownership policy is defined in CODEOWNERS."
@@ -0,0 +1,204 @@
1
+ name: PR Quality
2
+
3
+ on:
4
+ pull_request:
5
+ branches:
6
+ - main
7
+ types:
8
+ - opened
9
+ - reopened
10
+ - synchronize
11
+ - ready_for_review
12
+ push:
13
+ branches:
14
+ - main
15
+ workflow_dispatch:
16
+
17
+ permissions:
18
+ contents: read
19
+ pull-requests: write
20
+
21
+ concurrency:
22
+ group: pr-quality-${{ github.event.pull_request.number || github.ref }}
23
+ cancel-in-progress: true
24
+
25
+ env:
26
+ PYTHON_VERSION: "3.11"
27
+ COVERAGE_THRESHOLD: "60"
28
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
29
+ SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
30
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
31
+
32
+ jobs:
33
+ test:
34
+ name: Test
35
+ runs-on: ubuntu-latest
36
+
37
+ steps:
38
+ - name: Checkout repository
39
+ uses: actions/checkout@v4
40
+
41
+ - name: Set up Python
42
+ uses: actions/setup-python@v5
43
+ with:
44
+ python-version: ${{ env.PYTHON_VERSION }}
45
+
46
+ - name: Set up uv
47
+ uses: astral-sh/setup-uv@v5
48
+
49
+ - name: Install dependencies
50
+ run: uv sync --all-extras --dev
51
+
52
+ - name: Run unit tests with coverage
53
+ id: unit_tests
54
+ continue-on-error: true
55
+ run: |
56
+ uv run pytest tests/ \
57
+ --cov=openbox_langgraph \
58
+ --cov-report=xml:coverage.xml \
59
+ --cov-report=term-missing \
60
+ --cov-fail-under=${COVERAGE_THRESHOLD} \
61
+ -v
62
+
63
+ - name: Upload coverage report
64
+ if: ${{ always() && hashFiles('coverage.xml') != '' }}
65
+ uses: actions/upload-artifact@v4
66
+ with:
67
+ name: coverage-xml
68
+ path: coverage.xml
69
+ if-no-files-found: error
70
+
71
+ - name: Upload coverage to Codecov
72
+ if: ${{ always() && env.CODECOV_TOKEN != '' && hashFiles('coverage.xml') != '' }}
73
+ uses: codecov/codecov-action@v5
74
+ with:
75
+ files: ./coverage.xml
76
+ flags: unittests
77
+ name: pr-quality
78
+ fail_ci_if_error: true
79
+ verbose: true
80
+ token: ${{ env.CODECOV_TOKEN }}
81
+
82
+ - name: Fail job if tests failed
83
+ if: ${{ steps.unit_tests.outcome == 'failure' }}
84
+ run: exit 1
85
+
86
+ build:
87
+ name: Build
88
+ runs-on: ubuntu-latest
89
+ if: ${{ always() }}
90
+ needs:
91
+ - test
92
+
93
+ steps:
94
+ - name: Checkout repository
95
+ uses: actions/checkout@v4
96
+
97
+ - name: Set up Python
98
+ uses: actions/setup-python@v5
99
+ with:
100
+ python-version: ${{ env.PYTHON_VERSION }}
101
+
102
+ - name: Install build tooling
103
+ run: python -m pip install --upgrade build
104
+
105
+ - name: Build package
106
+ run: python -m build
107
+
108
+ - name: Upload build artifacts
109
+ uses: actions/upload-artifact@v4
110
+ with:
111
+ name: python-dist
112
+ path: dist/
113
+ if-no-files-found: error
114
+
115
+ sonarqube:
116
+ name: SonarQube
117
+ runs-on: ubuntu-latest
118
+ if: ${{ always() }}
119
+ needs:
120
+ - test
121
+
122
+ steps:
123
+ - name: Skip when SonarQube secrets are not configured
124
+ if: ${{ env.SONAR_TOKEN == '' || env.SONAR_HOST_URL == '' }}
125
+ run: echo "Skipping SonarQube because SONAR_TOKEN or SONAR_HOST_URL is not configured."
126
+
127
+ - name: Checkout repository
128
+ if: ${{ env.SONAR_TOKEN != '' && env.SONAR_HOST_URL != '' }}
129
+ uses: actions/checkout@v4
130
+ with:
131
+ fetch-depth: 0
132
+
133
+ - name: Download coverage report
134
+ if: ${{ env.SONAR_TOKEN != '' && env.SONAR_HOST_URL != '' }}
135
+ continue-on-error: true
136
+ uses: actions/download-artifact@v4
137
+ with:
138
+ name: coverage-xml
139
+ path: .
140
+
141
+ - name: Set up Java
142
+ if: ${{ env.SONAR_TOKEN != '' && env.SONAR_HOST_URL != '' }}
143
+ uses: actions/setup-java@v4
144
+ with:
145
+ distribution: temurin
146
+ java-version: "17"
147
+
148
+ - name: Cache SonarQube packages
149
+ if: ${{ env.SONAR_TOKEN != '' && env.SONAR_HOST_URL != '' }}
150
+ uses: actions/cache@v4
151
+ with:
152
+ path: ~/.sonar/cache
153
+ key: ${{ runner.os }}-sonar
154
+ restore-keys: ${{ runner.os }}-sonar
155
+
156
+ - name: SonarQube scan
157
+ if: ${{ env.SONAR_TOKEN != '' && env.SONAR_HOST_URL != '' }}
158
+ uses: SonarSource/sonarqube-scan-action@v7
159
+ env:
160
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
161
+ SONAR_TOKEN: ${{ env.SONAR_TOKEN }}
162
+ SONAR_HOST_URL: ${{ env.SONAR_HOST_URL }}
163
+
164
+ - name: SonarQube Quality Gate check
165
+ id: sonarqube_quality_gate
166
+ if: ${{ env.SONAR_TOKEN != '' && env.SONAR_HOST_URL != '' }}
167
+ continue-on-error: true
168
+ uses: SonarSource/sonarqube-quality-gate-action@master
169
+ with:
170
+ pollingTimeoutSec: 600
171
+ env:
172
+ SONAR_TOKEN: ${{ env.SONAR_TOKEN }}
173
+ SONAR_HOST_URL: ${{ env.SONAR_HOST_URL }}
174
+
175
+ - name: Print SonarQube result
176
+ if: ${{ always() && env.SONAR_TOKEN != '' && env.SONAR_HOST_URL != '' }}
177
+ shell: bash
178
+ run: |
179
+ status="${{ steps.sonarqube_quality_gate.outputs.quality-gate-status }}"
180
+
181
+ cat << 'EOF'
182
+ [QUALITY GATE] Checking NEW CODE conditions...
183
+ - FAIL IF: New Code Issues > 5
184
+ - FAIL IF: New Code Security Hotspots Reviewed < 100%
185
+ - FAIL IF: New Code Coverage < 60.0%
186
+ - FAIL IF: New Code Duplicated Lines > 3.0%
187
+
188
+ [QUALITY GATE] Checking OVERALL CODE conditions...
189
+ - FAIL IF: Overall High Severity Issues > 1
190
+ - FAIL IF: Overall Medium Severity Issues > 4
191
+ EOF
192
+
193
+ if [[ -z "${status}" ]]; then
194
+ status="UNKNOWN"
195
+ fi
196
+
197
+ echo "Quality Gate = ${status}"
198
+
199
+ - name: Fail job when SonarQube quality gate fails
200
+ if: ${{ always() && env.SONAR_TOKEN != '' && env.SONAR_HOST_URL != '' && steps.sonarqube_quality_gate.outcome == 'failure' }}
201
+ shell: bash
202
+ run: |
203
+ echo "SonarQube Quality Gate failed."
204
+ exit 1
@@ -0,0 +1,173 @@
1
+ name: PR Security
2
+
3
+ on:
4
+ pull_request:
5
+ branches:
6
+ - main
7
+ types:
8
+ - opened
9
+ - reopened
10
+ - synchronize
11
+ - ready_for_review
12
+ push:
13
+ branches:
14
+ - main
15
+ workflow_dispatch:
16
+
17
+ permissions:
18
+ actions: read
19
+ contents: read
20
+ pull-requests: read
21
+ security-events: write
22
+
23
+ concurrency:
24
+ group: pr-security-${{ github.event.pull_request.number || github.ref }}
25
+ cancel-in-progress: true
26
+
27
+ env:
28
+ GITLEAKS_VERSION: "8.30.0"
29
+
30
+ jobs:
31
+ trivy-fs:
32
+ name: Trivy Filesystem Scan
33
+ runs-on: ubuntu-latest
34
+
35
+ steps:
36
+ - name: Checkout repository
37
+ uses: actions/checkout@v4
38
+
39
+ - name: Set up Trivy
40
+ uses: aquasecurity/setup-trivy@e07451d2e059ed86c2870430ea286b3a9e0bf241
41
+ with:
42
+ cache: true
43
+ version: v0.69.2
44
+
45
+
46
+ - name: Run Trivy filesystem scan for console output
47
+ id: trivy_console
48
+ continue-on-error: true
49
+ shell: bash
50
+ run: |
51
+ set -euo pipefail
52
+ trivy fs . \
53
+ --scanners vuln,misconfig \
54
+ --vuln-type os,library \
55
+ --ignore-unfixed \
56
+ --severity HIGH,CRITICAL \
57
+ --include-dev-deps \
58
+ --format table \
59
+ --exit-code 1
60
+
61
+ - name: Run Trivy filesystem scan for SARIF
62
+ id: trivy_sarif
63
+ if: always()
64
+ continue-on-error: true
65
+ shell: bash
66
+ run: |
67
+ set -euo pipefail
68
+ trivy fs . \
69
+ --scanners vuln,misconfig \
70
+ --vuln-type os,library \
71
+ --ignore-unfixed \
72
+ --severity HIGH,CRITICAL \
73
+ --include-dev-deps \
74
+ --format sarif \
75
+ --output trivy-fs-results.sarif \
76
+ --exit-code 1
77
+
78
+ - name: Upload Trivy SARIF to GitHub Security
79
+ if: always()
80
+ continue-on-error: true
81
+ uses: github/codeql-action/upload-sarif@v4
82
+ with:
83
+ sarif_file: trivy-fs-results.sarif
84
+ category: trivy-fs
85
+
86
+ - name: Upload Trivy SARIF artifact
87
+ if: always()
88
+ uses: actions/upload-artifact@v4
89
+ with:
90
+ name: trivy-fs-results
91
+ path: trivy-fs-results.sarif
92
+ if-no-files-found: error
93
+
94
+ - name: Fail job when Trivy detects issues
95
+ if: always()
96
+ shell: bash
97
+ run: |
98
+ if [[ "${{ steps.trivy_console.outcome }}" == "failure" || "${{ steps.trivy_sarif.outcome }}" == "failure" ]]; then
99
+ echo "Trivy detected HIGH/CRITICAL findings."
100
+ exit 1
101
+ fi
102
+
103
+ gitleaks:
104
+ name: Gitleaks
105
+ runs-on: ubuntu-latest
106
+
107
+ steps:
108
+ - name: Checkout repository
109
+ uses: actions/checkout@v4
110
+ with:
111
+ fetch-depth: 0
112
+
113
+ - name: Run Gitleaks SARIF scan
114
+ id: gitleaks_scan
115
+ continue-on-error: true
116
+ uses: gitleaks/gitleaks-action@v2
117
+ env:
118
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
119
+ GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }}
120
+ GITLEAKS_CONFIG: .gitleaks.toml
121
+ GITLEAKS_VERSION: ${{ env.GITLEAKS_VERSION }}
122
+ GITLEAKS_ENABLE_COMMENTS: "false"
123
+ GITLEAKS_ENABLE_UPLOAD_ARTIFACT: "false"
124
+
125
+ - name: Ensure Gitleaks SARIF exists
126
+ if: always()
127
+ shell: bash
128
+ run: |
129
+ if [ ! -s results.sarif ]; then
130
+ cat > results.sarif <<'SARIF'
131
+ {
132
+ "$schema": "https://json.schemastore.org/sarif-2.1.0.json",
133
+ "version": "2.1.0",
134
+ "runs": [
135
+ {
136
+ "tool": {
137
+ "driver": {
138
+ "name": "gitleaks",
139
+ "informationUri": "https://github.com/gitleaks/gitleaks",
140
+ "rules": []
141
+ }
142
+ },
143
+ "results": []
144
+ }
145
+ ]
146
+ }
147
+ SARIF
148
+ fi
149
+
150
+ - name: Upload Gitleaks SARIF to GitHub Security
151
+ if: always()
152
+ continue-on-error: true
153
+ uses: github/codeql-action/upload-sarif@v4
154
+ with:
155
+ sarif_file: results.sarif
156
+ category: gitleaks
157
+
158
+ - name: Upload Gitleaks SARIF artifact
159
+ if: always()
160
+ uses: actions/upload-artifact@v4
161
+ with:
162
+ name: gitleaks-results
163
+ path: results.sarif
164
+ if-no-files-found: error
165
+
166
+ - name: Fail job when Gitleaks detects issues
167
+ if: always()
168
+ shell: bash
169
+ run: |
170
+ if [[ "${{ steps.gitleaks_scan.outcome }}" == "failure" ]]; then
171
+ echo "Gitleaks detected potential secrets."
172
+ exit 1
173
+ fi