ossuary-risk 0.1.0__tar.gz → 0.1.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 (34) hide show
  1. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/.gitignore +3 -0
  2. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/PKG-INFO +10 -10
  3. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/README.md +6 -6
  4. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/pyproject.toml +4 -4
  5. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/src/ossuary/sentiment/analyzer.py +20 -0
  6. ossuary_risk-0.1.0/validation_results.json +0 -250
  7. ossuary_risk-0.1.0/validation_results_100.json +0 -2438
  8. ossuary_risk-0.1.0/validation_results_cleaned.json +0 -566
  9. ossuary_risk-0.1.0/validation_results_expanded.json +0 -634
  10. ossuary_risk-0.1.0/validation_results_expanded_v2.json +0 -1334
  11. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/.env.example +0 -0
  12. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/docs/methodology.md +0 -0
  13. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/scripts/t1_comparison.py +0 -0
  14. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/scripts/validate.py +0 -0
  15. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/src/ossuary/__init__.py +0 -0
  16. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/src/ossuary/api/__init__.py +0 -0
  17. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/src/ossuary/api/main.py +0 -0
  18. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/src/ossuary/cli.py +0 -0
  19. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/src/ossuary/collectors/__init__.py +0 -0
  20. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/src/ossuary/collectors/base.py +0 -0
  21. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/src/ossuary/collectors/git.py +0 -0
  22. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/src/ossuary/collectors/github.py +0 -0
  23. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/src/ossuary/collectors/npm.py +0 -0
  24. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/src/ossuary/collectors/pypi.py +0 -0
  25. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/src/ossuary/db/__init__.py +0 -0
  26. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/src/ossuary/db/models.py +0 -0
  27. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/src/ossuary/db/session.py +0 -0
  28. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/src/ossuary/scoring/__init__.py +0 -0
  29. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/src/ossuary/scoring/engine.py +0 -0
  30. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/src/ossuary/scoring/factors.py +0 -0
  31. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/src/ossuary/scoring/reputation.py +0 -0
  32. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/src/ossuary/sentiment/__init__.py +0 -0
  33. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/tests/__init__.py +0 -0
  34. {ossuary_risk-0.1.0 → ossuary_risk-0.1.1}/tests/test_scoring.py +0 -0
@@ -62,6 +62,9 @@ repos/
62
62
  data/
63
63
  *.json.local
64
64
 
65
+ # Validation results
66
+ validation_results*.json
67
+
65
68
  # OS
66
69
  .DS_Store
67
70
  Thumbs.db
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ossuary-risk
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: OSS Supply Chain Risk Scoring - Where abandoned packages come to rest
5
- Project-URL: Homepage, https://github.com/anicka-net/ossuary
6
- Project-URL: Repository, https://github.com/anicka-net/ossuary
7
- Project-URL: Documentation, https://github.com/anicka-net/ossuary/blob/main/docs/methodology.md
5
+ Project-URL: Homepage, https://github.com/anicka-net/ossuary-risk
6
+ Project-URL: Repository, https://github.com/anicka-net/ossuary-risk
7
+ Project-URL: Documentation, https://github.com/anicka-net/ossuary-risk/blob/main/docs/methodology.md
8
8
  Author: Anicka
9
9
  License-Expression: MIT
10
10
  Keywords: oss,risk,scoring,security,supply-chain
@@ -165,8 +165,8 @@ Response:
165
165
 
166
166
  ```bash
167
167
  # Clone
168
- git clone https://github.com/anicka/ossuary.git
169
- cd ossuary
168
+ git clone https://github.com/anicka-net/ossuary-risk.git
169
+ cd ossuary-risk
170
170
 
171
171
  # Install with dev dependencies
172
172
  pip install -e ".[dev]"
@@ -221,12 +221,12 @@ REPOS_PATH=./repos
221
221
 
222
222
  ## Validation
223
223
 
224
- Validated on 93 packages (20 incidents + 73 controls):
224
+ Validated on 92 packages (20 incidents + 72 controls):
225
225
 
226
- - **Accuracy**: 91.4%
227
- - **Precision**: 92.9%
226
+ - **Accuracy**: 92.4%
227
+ - **Precision**: 100.0%
228
228
  - **Recall**: 65.0%
229
- - **F1 Score**: 0.76
229
+ - **F1 Score**: 0.79
230
230
 
231
231
  T-1 analysis confirms **100% predictive detection** of governance-detectable incidents before they occurred.
232
232
 
@@ -125,8 +125,8 @@ Response:
125
125
 
126
126
  ```bash
127
127
  # Clone
128
- git clone https://github.com/anicka/ossuary.git
129
- cd ossuary
128
+ git clone https://github.com/anicka-net/ossuary-risk.git
129
+ cd ossuary-risk
130
130
 
131
131
  # Install with dev dependencies
132
132
  pip install -e ".[dev]"
@@ -181,12 +181,12 @@ REPOS_PATH=./repos
181
181
 
182
182
  ## Validation
183
183
 
184
- Validated on 93 packages (20 incidents + 73 controls):
184
+ Validated on 92 packages (20 incidents + 72 controls):
185
185
 
186
- - **Accuracy**: 91.4%
187
- - **Precision**: 92.9%
186
+ - **Accuracy**: 92.4%
187
+ - **Precision**: 100.0%
188
188
  - **Recall**: 65.0%
189
- - **F1 Score**: 0.76
189
+ - **F1 Score**: 0.79
190
190
 
191
191
  T-1 analysis confirms **100% predictive detection** of governance-detectable incidents before they occurred.
192
192
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "ossuary-risk"
7
- version = "0.1.0"
7
+ version = "0.1.1"
8
8
  description = "OSS Supply Chain Risk Scoring - Where abandoned packages come to rest"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -53,9 +53,9 @@ dev = [
53
53
  ossuary = "ossuary.cli:app"
54
54
 
55
55
  [project.urls]
56
- Homepage = "https://github.com/anicka-net/ossuary"
57
- Repository = "https://github.com/anicka-net/ossuary"
58
- Documentation = "https://github.com/anicka-net/ossuary/blob/main/docs/methodology.md"
56
+ Homepage = "https://github.com/anicka-net/ossuary-risk"
57
+ Repository = "https://github.com/anicka-net/ossuary-risk"
58
+ Documentation = "https://github.com/anicka-net/ossuary-risk/blob/main/docs/methodology.md"
59
59
 
60
60
  [tool.hatch.build.targets.wheel]
61
61
  packages = ["src/ossuary"]
@@ -12,12 +12,29 @@ logger = logging.getLogger(__name__)
12
12
 
13
13
  # Keywords indicating maintainer frustration/burnout
14
14
  # These should be specific enough to avoid false positives on normal development discussions
15
+ #
16
+ # VALIDATION NOTE (Feb 2026):
17
+ # Tested against Marak Squires' actual Nov 2020 rant before colors.js/faker.js sabotage:
18
+ # "No More Free Works from Marak – Pay Me or Fork It. With all due respect,
19
+ # I am no longer going to support the Fortune 500 (and other smaller companies)
20
+ # with my free work."
21
+ #
22
+ # Key finding: VADER scored this as +0.676 (positive!) due to words like "support"
23
+ # and "opportunity". Keyword matching is essential - VADER alone would miss this.
24
+ #
25
+ # Added keywords based on this analysis:
26
+ # - "free work" / "my free work" - exact phrase from Marak's rant
27
+ # - "no longer support" - resignation signal
28
+ # - "stop supporting" - variation
29
+ #
15
30
  FRUSTRATION_KEYWORDS = [
16
31
  # Direct economic frustration (high signal)
17
32
  "not getting paid",
18
33
  "unpaid work",
19
34
  "free labor",
20
35
  "work for free",
36
+ "free work", # Added: exact phrase from Marak's 2020 rant
37
+ "my free work", # Added: more specific variant
21
38
  "donating my time",
22
39
  "corporate exploitation",
23
40
  "open source exploitation",
@@ -28,6 +45,9 @@ FRUSTRATION_KEYWORDS = [
28
45
  "stepping down",
29
46
  "giving up on this",
30
47
  "abandoning this project",
48
+ "no longer support", # Added: from Marak's "no longer going to support"
49
+ "stop supporting", # Added: variation
50
+ "stopping support", # Added: verb form variation
31
51
  # Economic frustration (moderate signal)
32
52
  "fortune 500",
33
53
  "pay developers",
@@ -1,250 +0,0 @@
1
- {
2
- "timestamp": "2026-02-01T17:38:28.683199",
3
- "total": 9,
4
- "accuracy": 0.8888888888888888,
5
- "precision": 1.0,
6
- "recall": 0.6666666666666666,
7
- "f1_score": 0.8,
8
- "confusion_matrix": {
9
- "TP": 2,
10
- "TN": 6,
11
- "FP": 0,
12
- "FN": 1
13
- },
14
- "by_attack_type": {
15
- "governance_failure": {
16
- "total": 1,
17
- "correct": 1
18
- },
19
- "maintainer_sabotage": {
20
- "total": 1,
21
- "correct": 1
22
- },
23
- "account_compromise": {
24
- "total": 1,
25
- "correct": 0
26
- },
27
- "control": {
28
- "total": 6,
29
- "correct": 6
30
- }
31
- },
32
- "results": [
33
- {
34
- "case": {
35
- "name": "event-stream",
36
- "ecosystem": "npm",
37
- "expected_outcome": "incident",
38
- "attack_type": "governance_failure",
39
- "incident_date": "2018-09-16",
40
- "cutoff_date": "2018-09-01",
41
- "notes": "Abandoned package, malicious maintainer gained access via social engineering",
42
- "repo_url": null
43
- },
44
- "score": 80,
45
- "risk_level": "CRITICAL",
46
- "predicted_outcome": "risky",
47
- "correct": true,
48
- "classification": "TP",
49
- "maintainer": "rolias",
50
- "reputation_score": 15,
51
- "reputation_tier": "UNKNOWN",
52
- "concentration": 75.0,
53
- "commits_last_year": 4,
54
- "protective_factors_total": 0,
55
- "error": null
56
- },
57
- {
58
- "case": {
59
- "name": "colors",
60
- "ecosystem": "npm",
61
- "expected_outcome": "incident",
62
- "attack_type": "maintainer_sabotage",
63
- "incident_date": "2022-01-08",
64
- "cutoff_date": "2022-01-01",
65
- "notes": "Marak intentionally sabotaged as protest against Fortune 500 companies",
66
- "repo_url": null
67
- },
68
- "score": 100,
69
- "risk_level": "CRITICAL",
70
- "predicted_outcome": "risky",
71
- "correct": true,
72
- "classification": "TP",
73
- "maintainer": "Marak",
74
- "reputation_score": 15,
75
- "reputation_tier": "UNKNOWN",
76
- "concentration": 100,
77
- "commits_last_year": 0,
78
- "protective_factors_total": -5,
79
- "error": null
80
- },
81
- {
82
- "case": {
83
- "name": "ua-parser-js",
84
- "ecosystem": "npm",
85
- "expected_outcome": "incident",
86
- "attack_type": "account_compromise",
87
- "incident_date": "2021-10-22",
88
- "cutoff_date": "2021-10-01",
89
- "notes": "Maintainer account compromised via email hijacking. Active project - governance metrics won't catch this.",
90
- "repo_url": null
91
- },
92
- "score": 25,
93
- "risk_level": "LOW",
94
- "predicted_outcome": "safe",
95
- "correct": false,
96
- "classification": "FN",
97
- "maintainer": "faisalman",
98
- "reputation_score": 15,
99
- "reputation_tier": "UNKNOWN",
100
- "concentration": 80.26315789473685,
101
- "commits_last_year": 152,
102
- "protective_factors_total": -25,
103
- "error": null
104
- },
105
- {
106
- "case": {
107
- "name": "chalk",
108
- "ecosystem": "npm",
109
- "expected_outcome": "safe",
110
- "attack_type": null,
111
- "incident_date": null,
112
- "cutoff_date": null,
113
- "notes": "High concentration but Sindre Sorhus has massive reputation and sponsors",
114
- "repo_url": null
115
- },
116
- "score": 0,
117
- "risk_level": "VERY_LOW",
118
- "predicted_outcome": "safe",
119
- "correct": true,
120
- "classification": "TN",
121
- "maintainer": "sindresorhus",
122
- "reputation_score": 90,
123
- "reputation_tier": "TIER_1",
124
- "concentration": 66.66666666666666,
125
- "commits_last_year": 6,
126
- "protective_factors_total": -60,
127
- "error": null
128
- },
129
- {
130
- "case": {
131
- "name": "lodash",
132
- "ecosystem": "npm",
133
- "expected_outcome": "safe",
134
- "attack_type": null,
135
- "incident_date": null,
136
- "cutoff_date": null,
137
- "notes": "Very popular, historically high concentration but visible and maintained",
138
- "repo_url": null
139
- },
140
- "score": 0,
141
- "risk_level": "VERY_LOW",
142
- "predicted_outcome": "safe",
143
- "correct": true,
144
- "classification": "TN",
145
- "maintainer": "jdalton",
146
- "reputation_score": 45,
147
- "reputation_tier": "TIER_2",
148
- "concentration": 42.857142857142854,
149
- "commits_last_year": 35,
150
- "protective_factors_total": -45,
151
- "error": null
152
- },
153
- {
154
- "case": {
155
- "name": "express",
156
- "ecosystem": "npm",
157
- "expected_outcome": "safe",
158
- "attack_type": null,
159
- "incident_date": null,
160
- "cutoff_date": null,
161
- "notes": "OpenJS Foundation, multiple maintainers, very active",
162
- "repo_url": null
163
- },
164
- "score": 0,
165
- "risk_level": "VERY_LOW",
166
- "predicted_outcome": "safe",
167
- "correct": true,
168
- "classification": "TN",
169
- "maintainer": "dependabot[bot]",
170
- "reputation_score": 30,
171
- "reputation_tier": "TIER_2",
172
- "concentration": 24.444444444444443,
173
- "commits_last_year": 135,
174
- "protective_factors_total": -65,
175
- "error": null
176
- },
177
- {
178
- "case": {
179
- "name": "requests",
180
- "ecosystem": "pypi",
181
- "expected_outcome": "safe",
182
- "attack_type": null,
183
- "incident_date": null,
184
- "cutoff_date": null,
185
- "notes": "Transitioned from Kenneth Reitz to PSF, successful community handoff",
186
- "repo_url": null
187
- },
188
- "score": 0,
189
- "risk_level": "VERY_LOW",
190
- "predicted_outcome": "safe",
191
- "correct": true,
192
- "classification": "TN",
193
- "maintainer": "kennethreitz",
194
- "reputation_score": 30,
195
- "reputation_tier": "TIER_2",
196
- "concentration": 36.36363636363637,
197
- "commits_last_year": 66,
198
- "protective_factors_total": -70,
199
- "error": null
200
- },
201
- {
202
- "case": {
203
- "name": "urllib3",
204
- "ecosystem": "pypi",
205
- "expected_outcome": "safe",
206
- "attack_type": null,
207
- "incident_date": null,
208
- "cutoff_date": null,
209
- "notes": "Org-owned, multiple maintainers, good governance",
210
- "repo_url": null
211
- },
212
- "score": 0,
213
- "risk_level": "VERY_LOW",
214
- "predicted_outcome": "safe",
215
- "correct": true,
216
- "classification": "TN",
217
- "maintainer": "shazow",
218
- "reputation_score": 30,
219
- "reputation_tier": "TIER_2",
220
- "concentration": 36.36363636363637,
221
- "commits_last_year": 110,
222
- "protective_factors_total": -80,
223
- "error": null
224
- },
225
- {
226
- "case": {
227
- "name": "django",
228
- "ecosystem": "pypi",
229
- "expected_outcome": "safe",
230
- "attack_type": null,
231
- "incident_date": null,
232
- "cutoff_date": null,
233
- "notes": "Django Software Foundation, many contributors, professional governance",
234
- "repo_url": null
235
- },
236
- "score": 0,
237
- "risk_level": "VERY_LOW",
238
- "predicted_outcome": "safe",
239
- "correct": true,
240
- "classification": "TN",
241
- "maintainer": "nessita",
242
- "reputation_score": 30,
243
- "reputation_tier": "TIER_2",
244
- "concentration": 16.666666666666664,
245
- "commits_last_year": 1602,
246
- "protective_factors_total": -45,
247
- "error": null
248
- }
249
- ]
250
- }