Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions PUBLIC_DATA_POLICY.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ distribution.
- Invented dimensions and quantities that do not reproduce a private project.
- Placeholder configuration such as `Example Fabricator` and `Example City, ST`.
- Product behavior and generic steel-domain terminology.
- Public demo media reviewed before publication and pinned in the scanner by exact
repository path and SHA-256 digest. Replacing it requires a new review and digest.
- Public gallery media reviewed before publication and pinned in the scanner by
exact repository path and SHA-256 digest. Replacing it requires a new review and
digest.
Comment on lines +15 to +17

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Require provenance and redistribution rights for gallery media.

A SHA-256 pin authenticates the bytes but does not prove that the repository owns or may redistribute them. Limit this exception to original/owned or properly licensed media, with provenance and redistribution rights documented before allowlisting.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@PUBLIC_DATA_POLICY.md` around lines 15 - 17, Update the public gallery media
policy to require documented provenance and redistribution rights before
allowlisting, limiting the exception to original, owned, or properly licensed
media. Retain the existing review and SHA-256 digest requirements for approved
media.


## Prohibited

Expand Down
Binary file added docs/assets/pi-steel-gallery.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@structupath/pi-steel",
"version": "0.2.2",
"description": "Structural steel estimating skills for the Pi coding agent — AISC takeoffs, bills of material, tonnage calcs, plate nesting with burn-table DXF output, and vendor RFQ generation.",
"description": "Structural steel estimating for Pi — validated takeoffs, plate nesting, guarded DXF output, and review-ready RFQ packages.",
"type": "module",
"keywords": [
"pi-package",
Expand All @@ -10,7 +10,6 @@
"structural-steel",
"estimating",
"takeoff",
"aisc",
"bom",
"rfq",
"construction",
Expand Down Expand Up @@ -48,7 +47,8 @@
"pi": {
"skills": [
"./skills"
]
],
"image": "https://raw.githubusercontent.com/StructuPath/pi-steel/main/docs/assets/pi-steel-gallery.webp"
Comment on lines +50 to +51

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Use an immutable image URL for released metadata.

The scanner pins the checked-in bytes, but this URL points at mutable main; an already-published package or catalog entry can therefore render a later asset. Point to the release commit SHA or another immutable/package-hosted URL so the reviewed image remains stable after release.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@package.json` around lines 50 - 51, Update the package metadata image URL in
package.json to reference an immutable release commit SHA or package-hosted
asset instead of the mutable main branch, preserving the reviewed image bytes
for published releases.

},
"files": [
"skills",
Expand All @@ -66,6 +66,7 @@
"DATA_PROVENANCE.md",
"DATA_PROVENANCE.json",
"docs/assets/pi-steel-demo.gif",
"docs/assets/pi-steel-gallery.webp",
"README.md",
"PUBLIC_DATA_POLICY.md",
"LICENSE"
Expand Down
2 changes: 2 additions & 0 deletions scripts/check-public-data.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
AUDITED_PUBLIC_BINARY_SHA256 = {
Path("docs/assets/pi-steel-demo.gif"):
"ae6ad7286fc5f1eca31e960d4ac4414b7a32a566b975ddacc7d662824c34d91c",
Path("docs/assets/pi-steel-gallery.webp"):
"9d8f2b1dedb00fa6c53c78f4578a12225f84bded4f7bbabe33182486372d12a8",
}
PATTERNS = {
"private operating-company claim": re.compile(
Expand Down
1 change: 1 addition & 0 deletions tests/test_package_contents.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def test_npm_dry_run_contains_runtime_contract_and_excludes_private_artifacts():
"DATA_PROVENANCE.json",
"PUBLIC_DATA_POLICY.md",
"docs/assets/pi-steel-demo.gif",
"docs/assets/pi-steel-gallery.webp",
"scripts/check-data-provenance.py",
"scripts/doctor.py",
"skills/_shared/schemas/estimate-package.schema.json",
Expand Down
26 changes: 15 additions & 11 deletions tests/test_public_data_policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,18 +79,22 @@ def test_scanner_checks_unlisted_text_and_unquoted_credentials(self):

self.assertTrue(any("credential assignment" in item for item in findings))

def test_audited_binary_requires_exact_path_and_hash(self):
def test_audited_binaries_require_exact_paths_and_hashes(self):
scanner = load_scanner()
relative = Path("docs/assets/pi-steel-demo.gif")
content = (ROOT / relative).read_bytes()

self.assertTrue(scanner.is_audited_public_binary(relative, content))
self.assertFalse(
scanner.is_audited_public_binary(relative, content + b"modified")
)
self.assertFalse(
scanner.is_audited_public_binary(Path("docs/assets/other.gif"), content)
)
for relative in scanner.AUDITED_PUBLIC_BINARY_SHA256:
with self.subTest(relative=relative):
content = (ROOT / relative).read_bytes()
self.assertTrue(
scanner.is_audited_public_binary(relative, content)
)
self.assertFalse(
scanner.is_audited_public_binary(relative, content + b"modified")
)
self.assertFalse(
scanner.is_audited_public_binary(
Path("docs/assets/other.bin"), content
)
)

def test_scanner_detects_high_confidence_secret_formats_without_echoing_value(self):
scanner = load_scanner()
Expand Down
Loading