Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix(py-isolation-api-server): use public accessors in get_stats#2165

Merged
imran-siddique merged 1 commit into
microsoft:mainfrom
aegis-initiative:fix/py-isolation-api-server-stats-accessors
May 12, 2026
Merged

fix(py-isolation-api-server): use public accessors in get_stats#2165
imran-siddique merged 1 commit into
microsoft:mainfrom
aegis-initiative:fix/py-isolation-api-server-stats-accessors

Conversation

@finnoybu

Copy link
Copy Markdown
Contributor

Summary

api/server.py's /api/v1/stats handler reached into three private attributes on the Hypervisor and VouchingEngine:

total_participants = sum(m.sso.participant_count for m in hv._sessions.values())
active_sagas       = sum(len(m.saga.active_sagas) for m in hv._sessions.values())
total_sessions     = len(hv._sessions)
total_vouches      = len(hv.vouching._vouches)

Reaching into another module's underscored containers makes any internal refactor (locking, indexing, storage backend) a breaking API change rather than an internal one. The fields are underscored on purpose.

Change

Adds three public accessors and switches get_stats to use them:

Accessor Returns
Hypervisor.sessions snapshot list[ManagedSession] of every managed session
Hypervisor.session_count total session count incl. archived/terminating
VouchingEngine.vouch_count total sponsorship-record count incl. released

Hypervisor.active_sessions already existed but filters via _active_ids, so it isn't equivalent to len(hv._sessions). The new accessors give the full registry, which is what get_stats needed. The snapshot form (list(self._sessions.values())) lets callers iterate without holding internal references.

Behaviour of get_stats is unchanged — same fields, same values, same ordering — and the iteration is now done once over hv.sessions rather than twice over hv._sessions.values().

Tests

Test Pins
test_session_count_empty Empty Hypervisor: session_count == 0, sessions == []
test_session_count_includes_terminated After terminate, active_sessions == 1 but session_count == 2
test_sessions_returns_snapshot_not_live_view A list captured before a later create_session does not grow
test_vouch_count_accessor Count tracks creation and survives release_bond (records aren't deleted)
$ PYTHONPATH=src python -m pytest tests/test_agent_manager.py tests/unit/test_liability.py -q
65 passed, 3 skipped in 0.70s

Full suite: 617 passed, 2 pre-existing failures in tests/unit/test_ring_improvements.py::TestBreachDetector confirmed unrelated to this change (verified by stashing and re-running on upstream/main).

Test plan

  • CI passes
  • All 65 test_agent_manager.py + test_liability.py tests pass
  • No regression in /api/v1/stats response shape or values
  • Hypervisor.sessions / session_count / VouchingEngine.vouch_count available to other internal callers that previously reached into _sessions / _vouches

Surfaced during independent audit conducted by @finnoybu (Ken Tannenbaum, AEGIS Initiative); [LOW, Python Isolation].

The `/api/v1/stats` endpoint reached into three private attributes:

  - `hv._sessions.values()` for participant / saga rollups
  - `len(hv._sessions)` for total session count
  - `len(hv.vouching._vouches)` for total vouch count

Reaching into private state from a different module makes refactoring
the internal containers (locking, indexing, storage backend) a breaking
API change rather than an internal one. The fields are all underscored
on purpose.

Adds three public accessors and switches `get_stats` to use them:

  - `Hypervisor.sessions` — snapshot list of every managed session
  - `Hypervisor.session_count` — total session count incl. archived
  - `VouchingEngine.vouch_count` — total sponsorship-record count

`Hypervisor.active_sessions` already existed; the new `sessions` /
`session_count` accessors give callers the *full* registry (active +
archived/terminating), which is what `get_stats` needed. The snapshot
form (`list(self._sessions.values())`) lets callers iterate without
holding internal references.

Behaviour of `get_stats` is unchanged — same fields, same values, same
ordering — and the iteration is now done once over `hv.sessions`
rather than twice over `hv._sessions.values()`.

Three regression tests cover the new accessors: empty-state count,
inclusion of terminated sessions, snapshot-semantics. One test covers
`VouchingEngine.vouch_count` including released bonds.
@github-actions github-actions Bot added tests agent-hypervisor agent-hypervisor package labels May 12, 2026
@github-actions

Copy link
Copy Markdown
🤖 AI Agent: security-scanner — View details

No security issues found.

@github-actions

Copy link
Copy Markdown
🤖 AI Agent: test-generator — `agent-governance-python/agent-hypervisor/src/hypervisor/api/server.py`

agent-governance-python/agent-hypervisor/src/hypervisor/api/server.py

  • test_stats_response_shape -- Validate that the /api/v1/stats response shape is correct after using public accessors.
  • test_stats_values -- Ensure that the values returned by /api/v1/stats are accurate and unchanged after the refactor.

agent-governance-python/agent-hypervisor/src/hypervisor/core.py

  • No gaps identified.

agent-governance-python/agent-hypervisor/src/hypervisor/liability/vouching.py

  • No gaps identified.

agent-governance-python/agent-hypervisor/tests/test_agent_manager.py

  • No gaps identified.

agent-governance-python/agent-hypervisor/tests/unit/test_liability.py

  • No gaps identified.

@github-actions

Copy link
Copy Markdown
🤖 AI Agent: code-reviewer — View details

TL;DR: 0 blockers, 0 warnings. No issues found. Clean change.

@github-actions github-actions Bot added the size/M Medium PR (< 200 lines) label May 12, 2026
@github-actions

Copy link
Copy Markdown
🤖 AI Agent: docs-sync-checker — Docs Sync

Docs Sync

  • sessions() in core.py -- missing docstring
  • session_count() in core.py -- missing docstring
  • vouch_count() in vouching.py -- missing docstring
  • README.md -- section on API changes needs update
  • CHANGELOG.md -- missing entry for behavioral changes in get_stats function

@github-actions

Copy link
Copy Markdown
🤖 AI Agent: breaking-change-detector — API Compatibility

API Compatibility

Severity Change Impact
Breaking Replaced direct access to private attributes (_sessions, _vouches) with public accessors (sessions, session_count, vouch_count) Callers relying on the previous private attributes may break if they expect direct access to those attributes.

@github-actions

Copy link
Copy Markdown

🟡 Contributor Check: MEDIUM

Check Result
Profile MEDIUM
Credential NONE
Overall MEDIUM

Automated check by AGT Contributor Check.

@github-actions github-actions Bot added the needs-review:MEDIUM Contributor check flagged MEDIUM risk label May 12, 2026
@github-actions

Copy link
Copy Markdown

PR Review Summary

Check Status Details
🔍 Code Review ✅ Passed No issues found
🛡️ Security Scan ✅ Passed No issues found
🔄 Breaking Changes ✅ Completed Analysis complete
📝 Docs Sync ✅ Completed Analysis complete
🧪 Test Coverage ✅ Completed Analysis complete

Verdict: ✅ Ready for human review

@imran-siddique imran-siddique merged commit 1a9b753 into microsoft:main May 12, 2026
13 of 14 checks passed
MohammadHaroonAbuomar pushed a commit to MohammadHaroonAbuomar/agt-acs that referenced this pull request Jun 1, 2026
…osoft#2165)

The `/api/v1/stats` endpoint reached into three private attributes:

  - `hv._sessions.values()` for participant / saga rollups
  - `len(hv._sessions)` for total session count
  - `len(hv.vouching._vouches)` for total vouch count

Reaching into private state from a different module makes refactoring
the internal containers (locking, indexing, storage backend) a breaking
API change rather than an internal one. The fields are all underscored
on purpose.

Adds three public accessors and switches `get_stats` to use them:

  - `Hypervisor.sessions` — snapshot list of every managed session
  - `Hypervisor.session_count` — total session count incl. archived
  - `VouchingEngine.vouch_count` — total sponsorship-record count

`Hypervisor.active_sessions` already existed; the new `sessions` /
`session_count` accessors give callers the *full* registry (active +
archived/terminating), which is what `get_stats` needed. The snapshot
form (`list(self._sessions.values())`) lets callers iterate without
holding internal references.

Behaviour of `get_stats` is unchanged — same fields, same values, same
ordering — and the iteration is now done once over `hv.sessions`
rather than twice over `hv._sessions.values()`.

Three regression tests cover the new accessors: empty-state count,
inclusion of terminated sessions, snapshot-semantics. One test covers
`VouchingEngine.vouch_count` including released bonds.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent-hypervisor agent-hypervisor package needs-review:MEDIUM Contributor check flagged MEDIUM risk size/M Medium PR (< 200 lines) tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants