Skip to content

Commit bf83996

Browse files
committed
Refactor attestation UI logic into helper functions
1 parent 43cd724 commit bf83996

1 file changed

Lines changed: 144 additions & 101 deletions

File tree

app.py

Lines changed: 144 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,134 @@ def _guess_app_name(original_filename: str) -> str:
8585
safe = name[:80]
8686
return safe
8787

88+
89+
def _render_attestation_section(
90+
*,
91+
uploaded_filename: str,
92+
file_hash: str,
93+
is_deb: bool,
94+
sig_detail: dict,
95+
sig_valid: bool,
96+
sig_info: dict,
97+
clam_detail: dict | None,
98+
clam_state: bool | None,
99+
clam_label: str,
100+
artifacts: dict,
101+
risk_score: int,
102+
risk_level: str,
103+
risk_evidence: list,
104+
) -> None:
105+
st.markdown("---")
106+
st.subheader("Attestation (Signed Scan Result)")
107+
if _ATTEST_IMPORT_ERROR:
108+
st.warning(f"Attestation unavailable: {_ATTEST_IMPORT_ERROR}")
109+
return
110+
111+
try:
112+
priv, pub, key_id = ensure_keypair()
113+
payload = build_scan_payload(
114+
original_filename=uploaded_filename,
115+
file_sha256=file_hash,
116+
is_deb=bool(is_deb),
117+
sig_detail=sig_detail,
118+
sig_valid=bool(sig_valid),
119+
sig_info=sig_info if isinstance(sig_info, dict) else {},
120+
clam_detail=clam_detail if isinstance(clam_detail, dict) else None,
121+
clam_state=clam_state,
122+
clam_label=str(clam_label or ""),
123+
artifacts=artifacts,
124+
risk_score=int(risk_score),
125+
risk_level=str(risk_level),
126+
risk_evidence=list(risk_evidence),
127+
)
128+
attestation = build_attestation(payload, private_key=priv, public_key=pub)
129+
130+
att_bytes = json.dumps(attestation, indent=2, ensure_ascii=False).encode("utf-8")
131+
pub_key_pem = attestation.get("signature", {}).get("public_key_pem", "")
132+
133+
c1, c2 = st.columns([1.2, 1.0])
134+
with c1:
135+
st.download_button(
136+
"Download attestation.json",
137+
data=att_bytes,
138+
file_name=f"attestation_{file_hash[:12]}.json",
139+
mime="application/json",
140+
)
141+
st.caption(f"Signed with key id: {key_id}")
142+
with c2:
143+
if isinstance(pub_key_pem, str) and pub_key_pem.strip():
144+
st.download_button(
145+
"Download public key (PEM)",
146+
data=pub_key_pem.encode("utf-8"),
147+
file_name=f"provity_attestation_pubkey_{key_id}.pem",
148+
mime="application/x-pem-file",
149+
)
150+
151+
with st.expander("Attestation preview"):
152+
st.json(attestation)
153+
except AttestationError as e:
154+
st.error(str(e))
155+
except Exception as e:
156+
st.error(f"Failed to build attestation: {e}")
157+
158+
159+
def _render_verify_attestation_tab() -> None:
160+
# ============================================================================
161+
# VERIFY TAB: NO DATABASE LOGGING
162+
# This tab performs read-only verification of attestations.
163+
# It does NOT call insert_scan_event() or write to the database.
164+
# All file uploads here are temporary and only used for verification.
165+
# ============================================================================
166+
167+
st.subheader("Verify Attestation")
168+
st.caption(
169+
"Upload attestation JSON and the original file. Public key (PEM) is optional if using the same Provity instance."
170+
)
171+
172+
if _ATTEST_IMPORT_ERROR:
173+
st.error(f"Attestation features unavailable: {_ATTEST_IMPORT_ERROR}")
174+
return
175+
176+
pubkey_file = st.file_uploader(
177+
"Issuer public key (PEM) - optional",
178+
type=["pem"],
179+
key="attestation_verify_pubkey",
180+
help="Optional. If not provided, uses local trusted issuer key (same Provity instance).",
181+
)
182+
att_file = st.file_uploader("Attestation file (JSON)", type=["json"], key="attestation_verify")
183+
orig_file = st.file_uploader("Original file", key="attestation_verify_file")
184+
185+
if att_file is None or orig_file is None:
186+
st.info("Upload attestation JSON and the original file to verify.")
187+
return
188+
189+
try:
190+
att_obj = parse_attestation_json(att_file.getvalue())
191+
pubkey_pem = pubkey_file.getvalue().decode("utf-8", errors="replace") if pubkey_file else None
192+
result = verify_attestation(att_obj, file_bytes=orig_file.getvalue(), public_key_pem=pubkey_pem)
193+
194+
if result.get("ok") is True:
195+
st.success("✅ Attestation verified")
196+
st.write(f"**Key ID:** {result.get('key_id')}")
197+
st.write(f"**Issuer:** {result.get('issuer_source', 'unknown')}")
198+
st.write(f"**File SHA-256:** {result.get('actual_sha256')}")
199+
200+
with st.expander("Verified payload"):
201+
st.json(result.get("payload") or {})
202+
else:
203+
st.error("❌ Verification failed")
204+
st.write(f"**Reason:** {result.get('reason')}")
205+
if result.get("expected_sha256"):
206+
st.write(f"**Expected SHA-256:** {result.get('expected_sha256')}")
207+
if result.get("actual_sha256"):
208+
st.write(f"**Actual SHA-256:** {result.get('actual_sha256')}")
209+
with st.expander("Attestation (raw)"):
210+
st.json(att_obj)
211+
except AttestationError as e:
212+
st.error(str(e))
213+
except Exception as e:
214+
st.error(f"Verification error: {e}")
215+
88216
# Page Configuration
89217
# NOTE: `page_icon` sets the browser tab favicon in Streamlit.
90218
st.set_page_config(page_title="Provity : Trusted Software Validator", page_icon="🛡️", layout="wide")
@@ -419,57 +547,21 @@ def _guess_app_name(original_filename: str) -> str:
419547
st.metric("Risk Score", f"{risk_score}/100")
420548
st.markdown("\n".join([f"- {item}" for item in risk_evidence]))
421549

422-
st.markdown("---")
423-
st.subheader("Attestation (Signed Scan Result)")
424-
if _ATTEST_IMPORT_ERROR:
425-
st.warning(f"Attestation unavailable: {_ATTEST_IMPORT_ERROR}")
426-
else:
427-
try:
428-
priv, pub, key_id = ensure_keypair()
429-
payload = build_scan_payload(
430-
original_filename=uploaded_file.name,
431-
file_sha256=file_hash,
432-
is_deb=bool(is_deb),
433-
sig_detail=sig_detail,
434-
sig_valid=bool(sig_valid),
435-
sig_info=sig_info if isinstance(sig_info, dict) else {},
436-
clam_detail=clam_detail if isinstance(clam_detail, dict) else None,
437-
clam_state=is_clean,
438-
clam_label=str(virus_name or ""),
439-
artifacts=artifacts,
440-
risk_score=int(risk_score),
441-
risk_level=str(risk_level),
442-
risk_evidence=list(risk_evidence),
443-
)
444-
attestation = build_attestation(payload, private_key=priv, public_key=pub)
445-
446-
att_bytes = json.dumps(attestation, indent=2, ensure_ascii=False).encode("utf-8")
447-
pub_key_pem = attestation.get("signature", {}).get("public_key_pem", "")
448-
449-
c1, c2 = st.columns([1.2, 1.0])
450-
with c1:
451-
st.download_button(
452-
"Download attestation.json",
453-
data=att_bytes,
454-
file_name=f"attestation_{file_hash[:12]}.json",
455-
mime="application/json",
456-
)
457-
st.caption(f"Signed with key id: {key_id}")
458-
with c2:
459-
if isinstance(pub_key_pem, str) and pub_key_pem.strip():
460-
st.download_button(
461-
"Download public key (PEM)",
462-
data=pub_key_pem.encode("utf-8"),
463-
file_name=f"provity_attestation_pubkey_{key_id}.pem",
464-
mime="application/x-pem-file",
465-
)
466-
467-
with st.expander("Attestation preview"):
468-
st.json(attestation)
469-
except AttestationError as e:
470-
st.error(str(e))
471-
except Exception as e:
472-
st.error(f"Failed to build attestation: {e}")
550+
_render_attestation_section(
551+
uploaded_filename=uploaded_file.name,
552+
file_hash=file_hash,
553+
is_deb=bool(is_deb),
554+
sig_detail=sig_detail,
555+
sig_valid=bool(sig_valid),
556+
sig_info=sig_info if isinstance(sig_info, dict) else {},
557+
clam_detail=clam_detail if isinstance(clam_detail, dict) else None,
558+
clam_state=is_clean,
559+
clam_label=str(virus_name or ""),
560+
artifacts=artifacts,
561+
risk_score=int(risk_score),
562+
risk_level=str(risk_level),
563+
risk_evidence=list(risk_evidence),
564+
)
473565

474566
# Persist scan event (best-effort)
475567
if db_enabled and db_log_scans:
@@ -510,57 +602,8 @@ def _guess_app_name(original_filename: str) -> str:
510602

511603

512604
with tab_verify:
513-
# ============================================================================
514-
# VERIFY TAB: NO DATABASE LOGGING
515-
# This tab performs read-only verification of attestations.
516-
# It does NOT call insert_scan_event() or write to the database.
517-
# All file uploads here are temporary and only used for verification.
518-
# ============================================================================
519-
520-
st.subheader("Verify Attestation")
521-
st.caption("Upload attestation JSON and the original file. Public key (PEM) is optional if using the same Provity instance.")
522-
523-
if _ATTEST_IMPORT_ERROR:
524-
st.error(f"Attestation features unavailable: {_ATTEST_IMPORT_ERROR}")
525-
else:
526-
pubkey_file = st.file_uploader(
527-
"Issuer public key (PEM) - optional",
528-
type=["pem"],
529-
key="attestation_verify_pubkey",
530-
help="Optional. If not provided, uses local trusted issuer key (same Provity instance).",
531-
)
532-
att_file = st.file_uploader("Attestation file (JSON)", type=["json"], key="attestation_verify")
533-
orig_file = st.file_uploader("Original file", key="attestation_verify_file")
534605

535-
if att_file is None or orig_file is None:
536-
st.info("Upload attestation JSON and the original file to verify.")
537-
else:
538-
try:
539-
att_obj = parse_attestation_json(att_file.getvalue())
540-
pubkey_pem = pubkey_file.getvalue().decode("utf-8", errors="replace") if pubkey_file else None
541-
result = verify_attestation(att_obj, file_bytes=orig_file.getvalue(), public_key_pem=pubkey_pem)
542-
543-
if result.get("ok") is True:
544-
st.success("✅ Attestation verified")
545-
st.write(f"**Key ID:** {result.get('key_id')}")
546-
st.write(f"**Issuer:** {result.get('issuer_source', 'unknown')}")
547-
st.write(f"**File SHA-256:** {result.get('actual_sha256')}")
548-
549-
with st.expander("Verified payload"):
550-
st.json(result.get("payload") or {})
551-
else:
552-
st.error("❌ Verification failed")
553-
st.write(f"**Reason:** {result.get('reason')}")
554-
if result.get("expected_sha256"):
555-
st.write(f"**Expected SHA-256:** {result.get('expected_sha256')}")
556-
if result.get("actual_sha256"):
557-
st.write(f"**Actual SHA-256:** {result.get('actual_sha256')}")
558-
with st.expander("Attestation (raw)"):
559-
st.json(att_obj)
560-
except AttestationError as e:
561-
st.error(str(e))
562-
except Exception as e:
563-
st.error(f"Verification error: {e}")
606+
_render_verify_attestation_tab()
564607

565608

566609
with tab_dashboard:

0 commit comments

Comments
 (0)