Fase A identity on PCB HEAD: operator fence, keep BOM/SPOF/EMI.

Replace Faradworks Inc. TOS/privacy/contact/metadata with Michele Bigi.
Dual-read pinscope_* keys; write periscope_* only. AGPL LICENSE and
GitHub fork parent unchanged. validate.py not edited.
This commit is contained in:
2026-09-20 12:41:17 +02:00
parent 1b3529501f
commit a63e5bd7ab
25 changed files with 1561 additions and 600 deletions
+15
View File
@@ -0,0 +1,15 @@
"""Fase A fence: PinScope identifiers that must be read, never written.
JWT issue uses JWT_ISSUER. Decode also accepts LEGACY_JWT_ISSUERS.
project.json may still contain pinscope_version; new writes use periscope_version.
See docs/development/PINSCOPE_FENCE.md. Do not import this from validate.py
or the finding engine — identity only.
"""
JWT_ISSUER = "periscope-local"
LEGACY_JWT_ISSUERS: tuple[str, ...] = ("pinscope-local",)
READ_JWT_ISSUERS: tuple[str, ...] = (JWT_ISSUER, *LEGACY_JWT_ISSUERS)
PROJECT_VERSION_FIELD = "periscope_version"
LEGACY_PROJECT_VERSION_FIELD = "pinscope_version"
+4 -3
View File
@@ -8,6 +8,7 @@ from typing import Any
import jwt
from backend.config import settings
from backend.pinscope_compat import JWT_ISSUER, READ_JWT_ISSUERS
ALGORITHM = "HS256"
TOKEN_TTL_DAYS = 30
@@ -21,7 +22,7 @@ def issue_token(user_id: str, email: str) -> str:
payload = {
"sub": user_id,
"email": email,
"iss": "periscope-local",
"iss": JWT_ISSUER,
"iat": now,
"exp": now + timedelta(days=TOKEN_TTL_DAYS),
}
@@ -32,8 +33,8 @@ def decode_token(token: str) -> dict[str, Any] | None:
secret = settings.auth_jwt_secret
if not secret:
return None
# Accept pre-rebrand issuer so existing sessions keep working.
for issuer in ("periscope-local", "pinscope-local"):
# Dual-read PinScope issuer; never write it (see pinscope_compat).
for issuer in READ_JWT_ISSUERS:
try:
return jwt.decode(
token,
+1 -1
View File
@@ -122,7 +122,7 @@ class ProjectMeta(BaseModel):
# Periscope app version that generated the project's report.
# Stamped on the first /start transition and preserved thereafter.
# Accept legacy pinscope_version from project.json written before the rebrand.
# Dual-read pinscope_version (PinScope fence); serialization uses periscope_version.
periscope_version: str | None = Field(
default=None,
validation_alias=AliasChoices("periscope_version", "pinscope_version"),