oss-trust-framework 0.5.1__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 (116) hide show
  1. oss_trust_framework-0.5.1/.env.example +24 -0
  2. oss_trust_framework-0.5.1/.github/approved-actions.json +46 -0
  3. oss_trust_framework-0.5.1/.github/quorum-config.json +228 -0
  4. oss_trust_framework-0.5.1/.github/scripts/post-trust-comment.js +78 -0
  5. oss_trust_framework-0.5.1/.github/scripts/quorum-engine.js +1240 -0
  6. oss_trust_framework-0.5.1/.github/workflows/dep-trust-check.yml +179 -0
  7. oss_trust_framework-0.5.1/.github/workflows/publish.yml +32 -0
  8. oss_trust_framework-0.5.1/.gitignore +28 -0
  9. oss_trust_framework-0.5.1/.venv-temp-placeholder/__init__.py +0 -0
  10. oss_trust_framework-0.5.1/.venv-temp-placeholder/checker.py +197 -0
  11. oss_trust_framework-0.5.1/.venv-temp-placeholder/cicd_audit/__init__.py +2 -0
  12. oss_trust_framework-0.5.1/.venv-temp-placeholder/cicd_audit/orphan_commits.py +210 -0
  13. oss_trust_framework-0.5.1/.venv-temp-placeholder/cicd_audit/pr_provenance.py +227 -0
  14. oss_trust_framework-0.5.1/.venv-temp-placeholder/cicd_audit/workflow_permissions.py +299 -0
  15. oss_trust_framework-0.5.1/.venv-temp-placeholder/cli.py +1 -0
  16. oss_trust_framework-0.5.1/.venv-temp-placeholder/config.py +24 -0
  17. oss_trust_framework-0.5.1/.venv-temp-placeholder/pipeline/__init__.py +0 -0
  18. oss_trust_framework-0.5.1/.venv-temp-placeholder/pipeline/cli.py +191 -0
  19. oss_trust_framework-0.5.1/.venv-temp-placeholder/pipeline/orchestrator.py +435 -0
  20. oss_trust_framework-0.5.1/.venv-temp-placeholder/sandbox/__init__.py +1 -0
  21. oss_trust_framework-0.5.1/.venv-temp-placeholder/sandbox/behavioral_patterns.py +303 -0
  22. oss_trust_framework-0.5.1/.venv-temp-placeholder/sbom/__init__.py +1 -0
  23. oss_trust_framework-0.5.1/.venv-temp-placeholder/signature/__init__.py +1 -0
  24. oss_trust_framework-0.5.1/.venv-temp-placeholder/signature/provenance.py +393 -0
  25. oss_trust_framework-0.5.1/.venv-temp-placeholder/trust/__init__.py +0 -0
  26. oss_trust_framework-0.5.1/.venv-temp-placeholder/trust/aggregator.py +202 -0
  27. oss_trust_framework-0.5.1/.venv-temp-placeholder/zeroday/__init__.py +0 -0
  28. oss_trust_framework-0.5.1/.venv-temp-placeholder/zeroday/validator.py +362 -0
  29. oss_trust_framework-0.5.1/BACKLOG.md +128 -0
  30. oss_trust_framework-0.5.1/CONTRIBUTING.md +182 -0
  31. oss_trust_framework-0.5.1/INSTALL_AND_TEST.md +1162 -0
  32. oss_trust_framework-0.5.1/LICENSE +21 -0
  33. oss_trust_framework-0.5.1/PKG-INFO +673 -0
  34. oss_trust_framework-0.5.1/README.md +621 -0
  35. oss_trust_framework-0.5.1/SECURITY.md +156 -0
  36. oss_trust_framework-0.5.1/config/pipeline.yaml +54 -0
  37. oss_trust_framework-0.5.1/config/policy.yaml +344 -0
  38. oss_trust_framework-0.5.1/config/sbom-baselines/PyPI/click.json +4 -0
  39. oss_trust_framework-0.5.1/config/sbom-baselines/PyPI/cryptography.json +5 -0
  40. oss_trust_framework-0.5.1/config/sbom-baselines/PyPI/httpx.json +9 -0
  41. oss_trust_framework-0.5.1/config/sbom-baselines/PyPI/pydantic.json +7 -0
  42. oss_trust_framework-0.5.1/config/sbom-baselines/PyPI/pyyaml.json +3 -0
  43. oss_trust_framework-0.5.1/config/sbom-baselines/PyPI/rich.json +7 -0
  44. oss_trust_framework-0.5.1/config/trusted_publishers.yaml +112 -0
  45. oss_trust_framework-0.5.1/correlation-rules/elastic/oss_trust_runtime_anomaly.json +44 -0
  46. oss_trust_framework-0.5.1/correlation-rules/sentinel/oss_trust_runtime_anomaly.json +51 -0
  47. oss_trust_framework-0.5.1/correlation-rules/splunk/oss_trust_runtime_anomaly.spl +82 -0
  48. oss_trust_framework-0.5.1/docs/gate5_gvisor_setup.md +162 -0
  49. oss_trust_framework-0.5.1/docs/index.html +2126 -0
  50. oss_trust_framework-0.5.1/oss_trust_framework/__init__.py +1 -0
  51. oss_trust_framework-0.5.1/oss_trust_framework/age_check/__init__.py +0 -0
  52. oss_trust_framework-0.5.1/oss_trust_framework/age_check/checker.py +197 -0
  53. oss_trust_framework-0.5.1/oss_trust_framework/cicd_audit/__init__.py +2 -0
  54. oss_trust_framework-0.5.1/oss_trust_framework/cicd_audit/orphan_commits.py +329 -0
  55. oss_trust_framework-0.5.1/oss_trust_framework/cicd_audit/pr_provenance.py +295 -0
  56. oss_trust_framework-0.5.1/oss_trust_framework/cicd_audit/workflow_permissions.py +249 -0
  57. oss_trust_framework-0.5.1/oss_trust_framework/cli.py +235 -0
  58. oss_trust_framework-0.5.1/oss_trust_framework/config.py +24 -0
  59. oss_trust_framework-0.5.1/oss_trust_framework/name_similarity/__init__.py +0 -0
  60. oss_trust_framework-0.5.1/oss_trust_framework/name_similarity/checker.py +264 -0
  61. oss_trust_framework-0.5.1/oss_trust_framework/pipeline/__init__.py +0 -0
  62. oss_trust_framework-0.5.1/oss_trust_framework/pipeline/cli.py +191 -0
  63. oss_trust_framework-0.5.1/oss_trust_framework/pipeline/orchestrator.py +282 -0
  64. oss_trust_framework-0.5.1/oss_trust_framework/sandbox/__init__.py +0 -0
  65. oss_trust_framework-0.5.1/oss_trust_framework/sandbox/behavioral_patterns.py +457 -0
  66. oss_trust_framework-0.5.1/oss_trust_framework/sandbox/runner.py +511 -0
  67. oss_trust_framework-0.5.1/oss_trust_framework/sandbox/test_gate5_sandbox_runner.py +322 -0
  68. oss_trust_framework-0.5.1/oss_trust_framework/sbom/__init__.py +1 -0
  69. oss_trust_framework-0.5.1/oss_trust_framework/sbom/differ.py +372 -0
  70. oss_trust_framework-0.5.1/oss_trust_framework/signature/__init__.py +1 -0
  71. oss_trust_framework-0.5.1/oss_trust_framework/signature/gpg.py +292 -0
  72. oss_trust_framework-0.5.1/oss_trust_framework/signature/provenance.py +461 -0
  73. oss_trust_framework-0.5.1/oss_trust_framework/trust/__init__.py +0 -0
  74. oss_trust_framework-0.5.1/oss_trust_framework/trust/aggregator.py +202 -0
  75. oss_trust_framework-0.5.1/oss_trust_framework/zeroday/__init__.py +0 -0
  76. oss_trust_framework-0.5.1/oss_trust_framework/zeroday/validator.py +362 -0
  77. oss_trust_framework-0.5.1/pyproject.toml +62 -0
  78. oss_trust_framework-0.5.1/registry/README.md +109 -0
  79. oss_trust_framework-0.5.1/registry/SCHEMA.md +151 -0
  80. oss_trust_framework-0.5.1/registry/index.json +6 -0
  81. oss_trust_framework-0.5.1/registry/packages/npm/lodash.json +26 -0
  82. oss_trust_framework-0.5.1/sbom/.gitkeep +12 -0
  83. oss_trust_framework-0.5.1/scripts/extract_dep_changes.py +359 -0
  84. oss_trust_framework-0.5.1/scripts/registry_ingest.py +368 -0
  85. oss_trust_framework-0.5.1/src/__init__.py +1 -0
  86. oss_trust_framework-0.5.1/src/age_check/__init__.py +0 -0
  87. oss_trust_framework-0.5.1/src/age_check/checker.py +197 -0
  88. oss_trust_framework-0.5.1/src/cicd_audit/__init__.py +2 -0
  89. oss_trust_framework-0.5.1/src/cicd_audit/orphan_commits.py +210 -0
  90. oss_trust_framework-0.5.1/src/cicd_audit/pr_provenance.py +227 -0
  91. oss_trust_framework-0.5.1/src/cicd_audit/workflow_permissions.py +299 -0
  92. oss_trust_framework-0.5.1/src/pipeline/__init__.py +0 -0
  93. oss_trust_framework-0.5.1/src/pipeline/cli.py +191 -0
  94. oss_trust_framework-0.5.1/src/pipeline/orchestrator.py +435 -0
  95. oss_trust_framework-0.5.1/src/sandbox/__init__.py +1 -0
  96. oss_trust_framework-0.5.1/src/sandbox/behavioral_patterns.py +457 -0
  97. oss_trust_framework-0.5.1/src/sbom/__init__.py +1 -0
  98. oss_trust_framework-0.5.1/src/signature/__init__.py +1 -0
  99. oss_trust_framework-0.5.1/src/signature/provenance.py +393 -0
  100. oss_trust_framework-0.5.1/src/trust/__init__.py +0 -0
  101. oss_trust_framework-0.5.1/src/trust/aggregator.py +202 -0
  102. oss_trust_framework-0.5.1/src/zeroday/__init__.py +0 -0
  103. oss_trust_framework-0.5.1/src/zeroday/validator.py +362 -0
  104. oss_trust_framework-0.5.1/tests/__init__.py +0 -0
  105. oss_trust_framework-0.5.1/tests/conftest.py +79 -0
  106. oss_trust_framework-0.5.1/tests/test_age_check.py +103 -0
  107. oss_trust_framework-0.5.1/tests/test_ai_hallucination.py +80 -0
  108. oss_trust_framework-0.5.1/tests/test_behavioral_patterns.py +217 -0
  109. oss_trust_framework-0.5.1/tests/test_cicd_audit.py +267 -0
  110. oss_trust_framework-0.5.1/tests/test_extract_dep_changes.py +156 -0
  111. oss_trust_framework-0.5.1/tests/test_license.py +75 -0
  112. oss_trust_framework-0.5.1/tests/test_pipeline.py +167 -0
  113. oss_trust_framework-0.5.1/tests/test_policy.py +128 -0
  114. oss_trust_framework-0.5.1/tests/test_registry_ingest.py +210 -0
  115. oss_trust_framework-0.5.1/tests/test_zeroday.py +104 -0
  116. oss_trust_framework-0.5.1/tests/test_zeroday_quorum.py +124 -0
@@ -0,0 +1,24 @@
1
+ # OSS Trust Framework β€” environment variables
2
+ # Copy to .env and fill in your values. Never commit .env to source control.
3
+
4
+ # GitHub token (for Advisory API and higher rate limits on Scorecard)
5
+ GITHUB_TOKEN=ghp_your_token_here
6
+
7
+ # SIEM / Splunk HEC
8
+ SIEM_HEC_ENDPOINT=https://your-splunk.example.com:8088/services/collector/event
9
+ SIEM_HEC_TOKEN=your-hec-token-here
10
+
11
+ # Ticket system (Jira)
12
+ JIRA_URL=https://your-org.atlassian.net
13
+ JIRA_USER=your-jira-email@example.com
14
+ JIRA_API_TOKEN=your-jira-token-here
15
+ TICKET_PROJECT_KEY=SEC
16
+
17
+ # Slack notifications
18
+ SLACK_WEBHOOK_URL=https://hooks.slack.com/services/xxx/yyy/zzz
19
+
20
+ # OSV API key (optional β€” public API works without a key)
21
+ OSV_API_KEY=
22
+
23
+ # Pipeline config path (override default)
24
+ PIPELINE_CONFIG_PATH=config/pipeline.yaml
@@ -0,0 +1,46 @@
1
+ {
2
+ "_comment": "Approved GitHub Actions pinned to commit SHAs. Gate 9 enforces this list.",
3
+ "_doc": "To add an action: find the commit SHA for the version tag at github.com/owner/repo/tags, then add an entry here.",
4
+ "approved": [
5
+ {
6
+ "action": "actions/checkout",
7
+ "sha": "11bd71901bbe5b1630ceea73d27597364c9af683",
8
+ "version_tag": "v4.2.2",
9
+ "approved_by": "security-team",
10
+ "approved_at": "2026-01-15",
11
+ "notes": "Standard checkout action"
12
+ },
13
+ {
14
+ "action": "actions/setup-python",
15
+ "sha": "65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236",
16
+ "version_tag": "v4.7.1",
17
+ "approved_by": "security-team",
18
+ "approved_at": "2026-01-15",
19
+ "notes": "Python environment setup"
20
+ },
21
+ {
22
+ "action": "actions/upload-artifact",
23
+ "sha": "65c4c4a1ddee5b72f698ffd38de1571e1f6a35c5",
24
+ "version_tag": "v4.6.0",
25
+ "approved_by": "security-team",
26
+ "approved_at": "2026-01-15",
27
+ "notes": "Artifact upload for trust-result.json"
28
+ },
29
+ {
30
+ "action": "actions/download-artifact",
31
+ "sha": "fa0a91b85d4f404e444306234a3fe6ee7e2dd2d5",
32
+ "version_tag": "v4.1.8",
33
+ "approved_by": "security-team",
34
+ "approved_at": "2026-01-15",
35
+ "notes": "Artifact download for quorum-override job"
36
+ },
37
+ {
38
+ "action": "actions/github-script",
39
+ "sha": "60a0d83039c74a4aee543508d2ffcb1c3799cdea",
40
+ "version_tag": "v7.0.1",
41
+ "approved_by": "security-team",
42
+ "approved_at": "2026-01-15",
43
+ "notes": "PR comment posting"
44
+ }
45
+ ]
46
+ }
@@ -0,0 +1,228 @@
1
+ {
2
+ "_comment": "OSS Trust Framework β€” Quorum Configuration v2.0",
3
+ "_doc": "Defines tiered quorum membership, application criticality classes, escalation paths, and reporting-only visibility roles. Member IDs are platform-specific: Discord = numeric user ID (18-19 digits), Teams = AAD Object ID (GUID), Slack = member ID (starts with U).",
4
+
5
+ "platform": "discord",
6
+
7
+ "_platform_member_id_formats": {
8
+ "discord": "Developer Mode ON β†’ right-click username anywhere β†’ Copy User ID (18-19 digit number)",
9
+ "teams": "Azure Portal β†’ Azure Active Directory β†’ Users β†’ select user β†’ Object ID (GUID)",
10
+ "slack": "Click user profile β†’ β€’β€’β€’ More actions β†’ Copy member ID (starts with U)"
11
+ },
12
+
13
+ "threshold": 0.5,
14
+ "_threshold_note": "Base fraction for simple majority. Overridden per-tier and per-rule in policy.yaml. 0.5 = strictly >50%. For 3 members: 2 votes needed. For 5 members: 3 votes needed.",
15
+
16
+ "deadlineHours": 24,
17
+ "_deadlineHours_note": "Default hours before an unresolved vote closes as EXPIRED (DENIED, fail-closed). Overridden per rule in policy.yaml.",
18
+
19
+ "_quorum_tier_model": {
20
+ "_overview": "Three-tier quorum model. Day-to-day approvals stay with the people closest to the code. Escalation brings in centralized security and legal only when the risk profile warrants it. Reporting visibility gives senior functions awareness without requiring their vote on routine decisions.",
21
+ "_tier_1": "Team Quorum β€” Application, operations, and development team members. First responders for routine dependency updates in their application domain. Simple majority of the team pool.",
22
+ "_tier_2": "AppSec Escalation β€” Application Security team members. Called in when trust score drops below threshold, behavior flags fire, or the team quorum deadlines without resolution. Can also be self-selected by team members when they want expert opinion.",
23
+ "_tier_3": "Enterprise Escalation β€” CISO and Legal. Reserved for mission-critical applications, policy violations, copyleft/commercial license changes, AI hallucination flags, and runtime anomaly revocations. Their involvement is defined in policy.yaml rules, not routine config."
24
+ },
25
+
26
+ "tiers": {
27
+
28
+ "_tier_1_team_quorum": {
29
+ "_description": "Day-to-day quorum members. These are the engineers, product owners, and operations staff who own the application and understand its dependency requirements. They vote on routine QUARANTINE/BLOCKED outcomes for packages in their domain. Add 3-7 people per application team for effective majority voting.",
30
+ "_who_to_add": [
31
+ "Lead developer or tech lead for the application",
32
+ "At least one senior engineer from the team",
33
+ "DevOps or platform engineer responsible for the deployment pipeline",
34
+ "Product owner or engineering manager (optional β€” gives business context to votes)",
35
+ "QA or release engineer if they have security awareness"
36
+ ],
37
+ "_who_not_to_add": [
38
+ "Anyone not familiar with the application's dependency stack",
39
+ "Do not add CISO or Legal here β€” their involvement is triggered by policy rules, not routine config",
40
+ "Avoid adding more than 7 people β€” decision fatigue sets in and abstentions rise"
41
+ ]
42
+ },
43
+
44
+ "team": {
45
+ "_comment": "Replace these placeholder IDs with real member IDs for your application team.",
46
+ "members": [
47
+ "111111111111111111",
48
+ "222222222222222222",
49
+ "333333333333333333"
50
+ ],
51
+ "threshold": 0.5,
52
+ "deadline_hours": 24,
53
+ "channel_id": "",
54
+ "_channel_id_note": "Optional: override the default channel with a team-specific approval channel. Leave empty to use the global DISCORD_CHANNEL_ID / SLACK_CHANNEL_ID."
55
+ },
56
+
57
+ "_tier_2_appsec": {
58
+ "_description": "Application Security team members. Called in automatically by policy rules when: trust score < configured threshold, behavior_change or author_reputation flags fire, team quorum expires without resolution, or the package is in a security-sensitive dependency class (auth, crypto, TLS). AppSec members can also be @mentioned manually by team members who want expert input before voting.",
59
+ "_who_to_add": [
60
+ "Application security engineers assigned to the application's business unit",
61
+ "Security architects familiar with the relevant technology stack",
62
+ "DevSecOps engineers embedded in the development team"
63
+ ]
64
+ },
65
+
66
+ "appsec": {
67
+ "_comment": "Replace with real AppSec team member IDs.",
68
+ "members": [
69
+ "444444444444444444",
70
+ "555555555555555555"
71
+ ],
72
+ "threshold": 0.5,
73
+ "deadline_hours": 12,
74
+ "_escalation_trigger_note": "AppSec is added to the quorum pool (not replacing the team) when policy rules match. The effective quorum becomes team + appsec members."
75
+ },
76
+
77
+ "_tier_3_enterprise": {
78
+ "_description": "Enterprise-level centralized functions. CISO and Legal are NOT routine quorum members. They are required members only when policy rules explicitly match β€” mission-critical application classes, copyleft license changes, AI hallucination attacks, runtime anomaly revocations, and any situation where the team + AppSec quorum has expired without resolution on a HIGH business impact application. They receive reporting visibility on all quorum events regardless of whether they voted."
79
+ },
80
+
81
+ "enterprise": {
82
+ "_comment": "Named roles for enterprise escalation. These map to policy.yaml conditions. Replace with real IDs.",
83
+ "members": [],
84
+ "_members_note": "Leave empty β€” enterprise members are added by named role in policy.yaml rules, not as default pool members.",
85
+ "named_roles": {
86
+ "CISO": "000000000000000000",
87
+ "DEPUTY_CISO": "000000000000000000",
88
+ "SECURITY_ARCH": "000000000000000000",
89
+ "LEGAL_COUNSEL": "000000000000000000",
90
+ "LEGAL_TECH": "000000000000000000",
91
+ "COMPLIANCE_OFFICER": "000000000000000000"
92
+ }
93
+ }
94
+ },
95
+
96
+ "application_criticality": {
97
+ "_description": "Application criticality class determines which tier is the starting quorum and when escalation is mandatory. Set the criticality class in the workflow env var APP_CRITICALITY or in a per-repo override.",
98
+
99
+ "classes": {
100
+
101
+ "standard": {
102
+ "_description": "Most internal tools, developer tooling, non-customer-facing applications. Standard quorum: team only. AppSec escalates on policy rule match.",
103
+ "starting_tier": "team",
104
+ "mandatory_appsec": false,
105
+ "mandatory_enterprise": false,
106
+ "deadline_hours": 24,
107
+ "threshold": 0.5,
108
+ "_examples": ["Internal admin tools", "Developer CI tooling", "Test automation frameworks"]
109
+ },
110
+
111
+ "elevated": {
112
+ "_description": "Customer-facing applications, applications handling PII, or applications with external API integrations. AppSec is added to the quorum pool from the start, not just on escalation.",
113
+ "starting_tier": "team_plus_appsec",
114
+ "mandatory_appsec": true,
115
+ "mandatory_enterprise": false,
116
+ "deadline_hours": 16,
117
+ "threshold": 0.5,
118
+ "_examples": ["Customer portals", "Mobile apps", "External APIs", "Applications processing PII or PHI"]
119
+ },
120
+
121
+ "mission_critical": {
122
+ "_description": "Applications that are core to business operations, handle financial transactions, involve regulated data (PII/PHI/PCI), or whose failure would have material business impact. Enterprise escalation (CISO or Legal) is required for any QUARANTINE or BLOCKED outcome. Full audit trail mandatory.",
123
+ "starting_tier": "team_plus_appsec",
124
+ "mandatory_appsec": true,
125
+ "mandatory_enterprise": true,
126
+ "deadline_hours": 8,
127
+ "threshold": 0.67,
128
+ "require_named_roles": ["CISO", "SECURITY_ARCH"],
129
+ "_examples": ["Core banking / payment processing", "Healthcare record systems", "Identity and authentication services", "Financial reporting systems", "Regulatory compliance systems"]
130
+ },
131
+
132
+ "critical_infrastructure": {
133
+ "_description": "Systems whose compromise would have safety, national security, or catastrophic business continuity implications. Unanimous approval required. CISO, Legal, and Compliance Officer must all be in the approving set.",
134
+ "starting_tier": "team_plus_appsec",
135
+ "mandatory_appsec": true,
136
+ "mandatory_enterprise": true,
137
+ "deadline_hours": 4,
138
+ "threshold": 1.0,
139
+ "require_named_roles": ["CISO", "SECURITY_ARCH", "LEGAL_COUNSEL", "COMPLIANCE_OFFICER"],
140
+ "_examples": ["SCADA / industrial control systems", "Air traffic control", "Power grid management", "Emergency response systems"]
141
+ }
142
+ }
143
+ },
144
+
145
+ "reporting_visibility": {
146
+ "_description": "Reporting-only roles receive a notification on every quorum event in their scope β€” regardless of the outcome, and regardless of whether they voted. They do NOT have voting rights in the default quorum. This gives CISO, Legal, and Compliance visibility into the full quorum picture without requiring their participation in every vote.",
147
+
148
+ "_how_it_works": "The quorum engine sends a summary DM or channel notification to all reporting-visibility IDs after every verdict is recorded. The notification includes the full audit row: package, version, trust score, verdict, voter detail, policy rule applied, and a link to the audit log row in Google Sheets.",
149
+
150
+ "always_notify": {
151
+ "_comment": "These IDs receive a summary of every quorum event across all applications and criticality classes. Suitable for CISO-level awareness.",
152
+ "members": [],
153
+ "_members_note": "Add CISO and Deputy CISO here for full-portfolio visibility."
154
+ },
155
+
156
+ "notify_on_elevated_and_above": {
157
+ "_comment": "These IDs receive summaries only for 'elevated' and 'mission_critical' application quorum events.",
158
+ "members": [],
159
+ "_members_note": "Add security architects and compliance officers here."
160
+ },
161
+
162
+ "notify_on_mission_critical_only": {
163
+ "_comment": "These IDs receive summaries only for 'mission_critical' and 'critical_infrastructure' quorum events.",
164
+ "members": [],
165
+ "_members_note": "Add Legal Counsel and Compliance Officer here."
166
+ },
167
+
168
+ "digest": {
169
+ "_description": "Weekly digest settings. A summary of all quorum events in the past 7 days is posted to the digest channel and optionally emailed.",
170
+ "enabled": false,
171
+ "channel_id": "",
172
+ "day_of_week": "monday",
173
+ "hour_utc": 9,
174
+ "_channel_note": "Set to a dedicated #security-quorum-digest channel visible to security leadership."
175
+ }
176
+ },
177
+
178
+ "escalation_paths": {
179
+ "_description": "Defines how and when the quorum escalates from team to AppSec to Enterprise, and what happens when a deadline expires without resolution.",
180
+
181
+ "team_to_appsec": {
182
+ "trigger_conditions": [
183
+ "deadline_expired_without_majority",
184
+ "trust_score < 50",
185
+ "flag_behavior_change == true",
186
+ "flag_author_reputation == true",
187
+ "flag_provenance_activity == true",
188
+ "slsa_level == 0 AND dependency_class IN [auth, crypto, tls]"
189
+ ],
190
+ "_trigger_note": "When any condition matches, AppSec members are added to the active quorum pool and the deadline resets. The team's prior votes are retained β€” a team DENY that already reached majority stands without AppSec input.",
191
+ "deadline_extension_hours": 12,
192
+ "notify_team_on_escalation": true
193
+ },
194
+
195
+ "appsec_to_enterprise": {
196
+ "trigger_conditions": [
197
+ "appsec_deadline_expired_without_majority",
198
+ "trust_score < 20",
199
+ "flag_ai_hallucination == true",
200
+ "flag_typosquatting == true",
201
+ "license_copyleft == true",
202
+ "runtime_anomaly == true",
203
+ "app_criticality IN [mission_critical, critical_infrastructure]"
204
+ ],
205
+ "deadline_extension_hours": 8,
206
+ "notify_appsec_on_escalation": true,
207
+ "require_named_roles": ["CISO", "SECURITY_ARCH"]
208
+ },
209
+
210
+ "on_total_expiry": {
211
+ "_description": "If all escalation tiers expire without a majority, the outcome is DENIED (fail-closed). A mandatory incident report is created.",
212
+ "action": "deny",
213
+ "create_incident": true,
214
+ "incident_channel_id": "",
215
+ "notify_roles": ["CISO", "SECURITY_ARCH", "COMPLIANCE_OFFICER"]
216
+ }
217
+ },
218
+
219
+ "_env_overrides": {
220
+ "_note": "Any field can be overridden at runtime via environment variables without changing this file.",
221
+ "QUORUM_PLATFORM": "discord | teams | slack",
222
+ "QUORUM_MEMBERS": "Comma-separated member IDs (overrides team tier members array)",
223
+ "QUORUM_THRESHOLD": "Float 0.0–1.0",
224
+ "QUORUM_DEADLINE_HOURS": "Integer hours",
225
+ "APP_CRITICALITY": "standard | elevated | mission_critical | critical_infrastructure",
226
+ "VOTE_SERVER_PORT": "Integer port for Teams/Slack callback server (default 3000)"
227
+ }
228
+ }
@@ -0,0 +1,78 @@
1
+ // .github/scripts/post-trust-comment.js
2
+ // Called by the dep-trust-check workflow via actions/github-script.
3
+ // Reads trust-result.json and posts or updates a PR comment.
4
+
5
+ const fs = require("fs");
6
+
7
+ module.exports = async ({ github, context }) => {
8
+ const result = JSON.parse(fs.readFileSync("trust-result.json", "utf8"));
9
+
10
+ const ICONS = {
11
+ approved: "βœ…",
12
+ blocked: "🚫",
13
+ quarantined: "⚠️",
14
+ hold: "⏸️",
15
+ pending_quorum: "πŸ”",
16
+ };
17
+ const icon = ICONS[result.outcome] ?? "❓";
18
+
19
+ // Build gate table rows β€” pipes are fine here; this is JS, not YAML
20
+ const gateRows = (result.gates ?? [])
21
+ .map((g) => `| ${g.gate} | ${g.passed ? "βœ…" : "❌"} | ${g.decision} |`)
22
+ .join("\n");
23
+
24
+ const gateTable = gateRows.length
25
+ ? `
26
+ ### Gate results
27
+ | Gate | Passed | Decision |
28
+ |------|--------|----------|
29
+ ${gateRows}`
30
+ : "";
31
+
32
+ const advisories = (result.advisories ?? []).length
33
+ ? `
34
+ ### Advisories
35
+ ${result.advisories.map((a) => `- **${a.id}** β€” ${a.summary}`).join("\n")}`
36
+ : "";
37
+
38
+ const body = [
39
+ `## ${icon} OSS Trust Framework β€” \`${result.package}@${result.version}\``,
40
+ `**Outcome:** \`${result.outcome.toUpperCase()}\` `,
41
+ `**Message:** ${result.message}`,
42
+ gateTable,
43
+ advisories,
44
+ `\n<sub>Ecosystem: \`${result.ecosystem}\` Β· Run: [${context.runId}](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})</sub>`,
45
+ ]
46
+ .filter(Boolean)
47
+ .join("\n");
48
+
49
+ // Find an existing bot comment for this package to update rather than spam
50
+ const marker = `<!-- oss-trust:${result.package}@${result.version} -->`;
51
+ const fullBody = `${marker}\n${body}`;
52
+
53
+ const { data: comments } = await github.rest.issues.listComments({
54
+ owner: context.repo.owner,
55
+ repo: context.repo.repo,
56
+ issue_number: context.issue.number,
57
+ });
58
+
59
+ const existing = comments.find(
60
+ (c) => c.user.type === "Bot" && c.body.includes(marker)
61
+ );
62
+
63
+ if (existing) {
64
+ await github.rest.issues.updateComment({
65
+ owner: context.repo.owner,
66
+ repo: context.repo.repo,
67
+ comment_id: existing.id,
68
+ body: fullBody,
69
+ });
70
+ } else {
71
+ await github.rest.issues.createComment({
72
+ owner: context.repo.owner,
73
+ repo: context.repo.repo,
74
+ issue_number: context.issue.number,
75
+ body: fullBody,
76
+ });
77
+ }
78
+ };