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
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ Format: [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
## [Unreleased]

### Changed
- Kept PortfolioTruth `0.11.0` and
`GitHubSecurityCoverageReceiptV1` read-compatible while adding normalized
provider reason codes, explicit completed-zero semantics, producer-commit
binding, and a same-pass GitHub default-branch/head observation for every
repository in the security cohort. Missing credentials and stale or partial
observations now stay fail-closed instead of presenting zero as clean. The
development dependency also bounds Ruff below `0.16` so CI retains its
reviewed lint contract until the expanded ruleset is migrated separately.
- Migrated `config/portfolio-catalog.yaml` and the example catalog from
`intended_disposition` to `operating_path` (179 + 3 entries; identity value
mapping — `resolve_declared_operating_path` already treated disposition
Expand Down
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ dependencies = [
[project.optional-dependencies]
dev = [
"pytest>=8.0",
"ruff>=0.4",
# Ruff 0.16 enables a materially wider ruleset under the repository's
# implicit selection; keep CI on the reviewed 0.15 line until that migration
# is handled as its own cleanup change.
"ruff>=0.4,<0.16",
"mypy>=1.10",
"mutmut>=2.5",
"responses>=0.25",
Expand Down
10 changes: 8 additions & 2 deletions src/app/portfolio_truth.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from pathlib import Path
from typing import Any

from src.cache import ResponseCache
from src.cli_output import print_info
from src.github_security_coverage import DEFAULT_EXPECTED_GITHUB_COHORT_COUNT
from src.portfolio_context_recovery import (
Expand Down Expand Up @@ -68,6 +67,9 @@ def run_portfolio_truth_mode(args: Any) -> None:
"portfolio_truth_security_cohort_count",
DEFAULT_EXPECTED_GITHUB_COHORT_COUNT,
),
expected_producer_commit=(
producer_evidence.commit if producer_evidence is not None else None
),
)
if loaded_security is not None:
security_alerts_by_name = loaded_security.entries_by_full_name
Expand All @@ -77,6 +79,7 @@ def run_portfolio_truth_mode(args: Any) -> None:
"produced_at": loaded_security.produced_at,
"state": loaded_security.receipt_state,
"age_hours": loaded_security.age_hours,
"producer_commit": loaded_security.producer_commit,
"cohort_policy": loaded_security.cohort_policy,
"cohort_repository_count": len(
loaded_security.cohort_repositories
Expand All @@ -86,7 +89,10 @@ def run_portfolio_truth_mode(args: Any) -> None:
repo_status_by_name = load_live_repo_status_by_name(
username=args.username,
token=getattr(args, "token", None),
cache=None if getattr(args, "no_cache", False) else ResponseCache(),
# Lifecycle state is reconciled against the fresh security receipt.
# Do not let the general API response cache masquerade as a newer
# repository-status observation.
cache=None,
)
if repo_status_by_name is None:
repo_status_by_name = load_repo_status_from_audit_by_name(
Expand Down
Loading