Skip to content

test: prove the non-root AgentX path in the distribution containers - #23

Merged
marcinpsk merged 1 commit into
developfrom
packaging/non-root-path
Sep 15, 2026
Merged

marcinpsk merged 1 commit into
developfrom
packaging/non-root-path

Conversation

@marcinpsk

@marcinpsk marcinpsk commented Sep 15, 2026

Copy link
Copy Markdown
Owner

The user documentation and the manual page named agentXPerms as the
supported way to run the subagent without root. Nobody had run it, so an
operator was following an untested instruction.

A shared scenario now runs in every distribution container. It starts a
real master, creates a system user and group, runs the packaged binary as
that user with the packaged configuration, and walks ifStackTable. Both
distribution test scripts call it after their install checks and before
their removal checks. A packaging policy test finds every distribution
script and requires the call, so a new distribution cannot skip it.

The recipe in the first draft did not work. net-snmp applies chmod and
chown to the AgentX socket only. It never changes the group of the parent
directory, so a directory mode of 0770 left /var/agentx owned by root and
group root, and the subagent could not traverse it. The directive now uses
0755 for the directory, which grants traverse, and the socket carries the
access control as mode 0660 owned by root and the subagent group.

net-snmp also creates the directory only when the bind fails with ENOENT,
so an existing /var/agentx keeps its mode and the directory mode in the
directive is ignored. The documents now say that, because an operator with
a previous snmpd installation meets exactly that case.

The scenario proves what it claims. It walks the table before the subagent
starts and requires no rows, so the rows can only come from the child it
started. It reads the real and effective user IDs of that child from /proc
and rejects zero. It reads the container interfaces from /sys/class/net and
requires the boundary rows of exactly those interfaces, so a fabricated
walk cannot pass. It waits for the socket mode and ownership together with
the socket itself, because net-snmp creates the socket before it applies
them.

Cleanup checks that the user and the group still exist before it removes
them. On Debian, userdel removes an empty primary group with the same name,
so the following groupdel failed and aborted the package test after the
scenario reported success.

The documents state the evidence boundary. The containers run no service
manager, so the systemd drop-in, the supplementary group through systemd,
and the unit sandbox are not exercised. The shipped unit keeps User=root.

The distribution test scripts no longer install iproute, which no command
in them used.

Closes #19

Summary by CodeRabbit

  • Documentation

    • Added instructions for running the service as a non-root user, including required permissions, account setup, and systemd configuration.
    • Clarified that the packaged service runs as root by default.
    • Documented deployment requirements and testing limitations for non-root and sandboxed operation.
  • Testing

    • Added end-to-end validation for non-root AgentX operation, including socket permissions, registration, and published interface data.
    • Updated Debian and RPM package checks to cover non-root operation.

The user documentation and the manual page named agentXPerms as the
supported way to run the subagent without root. Nobody had run it, so an
operator was following an untested instruction.

A shared scenario now runs in every distribution container. It starts a
real master, creates a system user and group, runs the packaged binary as
that user with the packaged configuration, and walks ifStackTable. Both
distribution test scripts call it after their install checks and before
their removal checks. A packaging policy test finds every distribution
script and requires the call, so a new distribution cannot skip it.

The recipe in the first draft did not work. net-snmp applies chmod and
chown to the AgentX socket only. It never changes the group of the parent
directory, so a directory mode of 0770 left /var/agentx owned by root and
group root, and the subagent could not traverse it. The directive now uses
0755 for the directory, which grants traverse, and the socket carries the
access control as mode 0660 owned by root and the subagent group.

net-snmp also creates the directory only when the bind fails with ENOENT,
so an existing /var/agentx keeps its mode and the directory mode in the
directive is ignored. The documents now say that, because an operator with
a previous snmpd installation meets exactly that case.

The scenario proves what it claims. It walks the table before the subagent
starts and requires no rows, so the rows can only come from the child it
started. It reads the real and effective user IDs of that child from /proc
and rejects zero. It reads the container interfaces from /sys/class/net and
requires the boundary rows of exactly those interfaces, so a fabricated
walk cannot pass. It waits for the socket mode and ownership together with
the socket itself, because net-snmp creates the socket before it applies
them.

Cleanup checks that the user and the group still exist before it removes
them. On Debian, userdel removes an empty primary group with the same name,
so the following groupdel failed and aborted the package test after the
scenario reported success.

The documents state the evidence boundary. The containers run no service
manager, so the systemd drop-in, the supplementary group through systemd,
and the unit sandbox are not exercised. The shipped unit keeps User=root.

The distribution test scripts no longer install iproute, which no command
in them used.

Closes #19
@coderabbitai

coderabbitai Bot commented Sep 15, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 1b4e06f3-ba78-452b-98c0-7d58302746b8

📥 Commits

Reviewing files that changed from the base of the PR and between af0244f and 04a638a.

📒 Files selected for processing (6)
  • README.md
  • packaging/agentx-ifstack.8
  • packaging/non-root-agentx.sh
  • packaging/test-deb.sh
  • packaging/test-rpm.sh
  • packaging/test_policy.py

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


Walkthrough

The change documents non-root AgentX operation, adds a shared end-to-end permission and table-validation scenario, runs it from Debian and RPM package tests, and adds policy checks for the documentation, safety checks, process identity, and diagnostic output.

Changes

Non-root AgentX operation

Layer / File(s) Summary
Permission model documentation
README.md, packaging/agentx-ifstack.8
Documents root as the default and specifies the system user, group, agentXPerms, /var/agentx traversal, systemd drop-in, and package-test limitations.
Scenario setup and cleanup
packaging/non-root-agentx.sh
Adds an isolated scenario that validates prerequisites, creates the system identity, starts snmpd, and cleans up processes, users, groups, sockets, directories, and temporary files.
Socket access and table validation
packaging/non-root-agentx.sh
Verifies socket ownership and permissions, starts the subagent with setpriv, confirms a non-root UID, and validates ordered ifStackTable boundary rows.
Distribution wiring and policy checks
packaging/test-deb.sh, packaging/test-rpm.sh, packaging/test_policy.py
Installs the required SNMP tools, runs the shared scenario in both package tests, and enforces the scenario, documentation, safety, identity, and diagnostic-output requirements.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Other

Sequence Diagram(s)

sequenceDiagram
  participant PackageTest
  participant Snmpd
  participant AgentxIfstack
  participant Snmpwalk
  PackageTest->>Snmpd: start with AgentX socket permissions
  Snmpd-->>PackageTest: create /var/agentx/master
  PackageTest->>AgentxIfstack: start with setpriv as agentx-ifstack
  AgentxIfstack->>Snmpd: register ifStackTable
  PackageTest->>Snmpwalk: walk ifStackTable
  Snmpwalk-->>PackageTest: return validated boundary rows
Loading

Merge Risk: ⚪ Minimal · up to 04a63

The non-root package scenario is wired into both distribution test paths, and its RPM dependency is present. No concrete merge-blocking issue remains.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning Issue #19 requires the permission-directive argument order to come from the container manual page. packaging/non-root-agentx.sh renders and prints the installed snmpd.conf manual section, but it h… Parse and validate the installed manual page before creating the master configuration. Use the argument order obtained from that manual page, and fail the scenario when the manual is missing or does not provide the expected directive syntax…
Docstring Coverage ⚠️ Warning Docstring coverage is 63.64% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 11 functions across 4 files. (2 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding distribution-container coverage for the non-root AgentX path.
Out of Scope Changes check ✅ Passed The changes stay within issue #19. They add the shared non-root container scenario, distribution test integration, packaging policy coverage, required documentation, and validation that the shipped un…
Full details: Linked Issues check

Explanation

Issue #19 requires the permission-directive argument order to come from the container manual page. packaging/non-root-agentx.sh renders and prints the installed snmpd.conf manual section, but it hard-codes agentXPerms 0660 0755 root $subagent_group in the generated configuration. The manual output is diagnostic only, so the scenario does not prove that its directive order matches the installed manual. The other stated objectives are implemented by the shared scenario, distribution-script calls, policy checks, documentation, and root-default unit configuration.

Resolution

Parse and validate the installed manual page before creating the master configuration. Use the argument order obtained from that manual page, and fail the scenario when the manual is missing or does not provide the expected directive syntax.

Full details: Docstring Coverage

Explanation

Docstring coverage is 63.64% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 11 functions across 4 files. (2 skipped: 2 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch packaging/non-root-path
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch packaging/non-root-path

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

A rabbit reads each line,
The patch grows clear beneath the moon,
Small changes hop in place,
Tests guard the garden path,
Reviews bloom before the dawn.

Comment @coderabbitai help to get the list of available commands.

@marcinpsk
marcinpsk merged commit 2174c2b into develop Sep 15, 2026
11 checks passed
@marcinpsk
marcinpsk deleted the packaging/non-root-path branch September 15, 2026 15:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant