Skip to content

[WIP] Introduce limeCtl wrapper over keylime_tenant and keylimectl - #1129

Open
kkaarreell wants to merge 13 commits into
mainfrom
ks_limeCtl
Open

kkaarreell wants to merge 13 commits into
mainfrom
ks_limeCtl

Conversation

@kkaarreell

@kkaarreell kkaarreell commented Aug 25, 2026 •

Copy link
Copy Markdown
Collaborator

Summary by Sourcery

Introduce limeCtl as a unified, keylimectl-shaped interface for Keylime management and migrate the test suite to use it.

New Features:

  • Add a unified limeCtl management interface for agent, runtime policy, and measured-boot policy operations.
  • Support switching limeCtl between keylime_tenant translation and direct keylimectl execution.

Enhancements:

  • Migrate functional, multihost, container, regression, and update tests from direct keylime_tenant commands to limeCtl.
  • Update helper usage to support limeCtl calls across subshell-based test execution.

Build:

  • Adjust Rust Keylime installation feature selection to enable the keylimectl runtime features explicitly while excluding deprecated features.

Documentation:

  • Document the limeCtl command interface and the keylime_tenant-to-keylimectl migration.

Tests:

  • Update broad test coverage to exercise the new limeCtl command syntax for agent enrollment, status, listing, removal, updates, and measured-boot policy management.

Chores:

  • Remove obsolete upstream test plan definitions and update remaining plan metadata.

@kkaarreell kkaarreell self-assigned this Aug 25, 2026
@sourcery-ai

sourcery-ai Bot commented Aug 25, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

Introduces limeCtl as a documented, keylimectl-shaped abstraction that translates agent and policy operations to keylime_tenant or optionally passes them through to keylimectl, then migrates the test suite and helper usage to the new interface.

File-Level Changes

Change Details Files
Add a unified limeCtl shell wrapper with a keylimectl-compatible command structure and keylime_tenant translation by default.
  • Parse verifier and registrar connection options before subcommands.
  • Dispatch agent operations to translated tenant commands, including add, update, remove, status, list, and reactivate.
  • Dispatch runtime-policy and measured-boot policy CRUD operations to the corresponding tenant commands.
  • Support switching to direct keylimectl passthrough through limeCtlCommand.
  • Document the wrapper interface and clean up temporary translated global options after dispatch.
Library/test-helpers/lib.sh
Migrate test invocations from raw keylime_tenant commands to the new wrapper interface.
  • Replace agent enrollment, update, removal, and listing calls with limeCtl subcommands and long-form options.
  • Replace measured-boot policy management calls with the wrapper's policy-oriented commands.
  • Preserve expected success and failure assertions across functional, multihost, container, update, sanity, and regression tests.
  • Export the wrapper and helper functions for use in the nested timeout shell.
Multihost/basic-push-attestation/test.sh
Multihost/upgrade/basic-attestation/test.sh
container/functional/keylime_agent_container-basic-attestation/test.sh
container/functional/keylime_verifier_registrar_container-basic-attestation/test.sh
functional/agent-registration-with-non-default-tpm-algorithms/test.sh
functional/agent-resilience-and-reattestation/test.sh
functional/attestation-mode-mismatch/test.sh
functional/basic-attestation-with-concatenated-certificates/test.sh
functional/basic-attestation-with-ima-signatures/test.sh
functional/db-mariadb-sanity-on-localhost/test.sh
functional/db-mysql-sanity-on-localhost/test.sh
functional/db-postgresql-sanity-on-localhost/test.sh
functional/durable-attestion-sanity-on-localhost/test.sh
functional/ek-cert-use-ek_check_script/test.sh
functional/ek-cert-use-ek_handle-custom-ca_certs/test.sh
functional/install-rpm-with-ima-signature/test.sh
functional/measured-boot-policy-sanity/test.sh
functional/measured-boot-swtpm-sanity/test.sh
functional/push-attestation-on-localhost/test.sh
functional/push-authentication-basic/test.sh
functional/push-authentication-cross-agent-attestation/test.sh
functional/push-authentication-persistence/test.sh
functional/push-authentication-protocol/test.sh
functional/push-authentication-token-lifecycle/test.sh
functional/push-model-attestation-with-postgresql-db/test.sh
functional/tpm-issuer-cert-using-ecc/test.sh
functional/tpm_policy-sanity-on-localhost/test.sh
functional/use-multiple-ima-sign-verification-keys/test.sh
functional/verifier_registrar_unreachable/test.sh
regression/CVE-2023-3674/test.sh
regression/cannot-use-mTLS-cert-on-server-admin-api-endpoint/test.sh
regression/cve-2023-38200/test.sh
regression/issue-1380-agent-removed-and-re-added/test.sh
sanity/opened-conf-files/test.sh
update/basic-attestation-on-localhost/test.sh
Add migration guidance for converting tenant commands to the unified wrapper.
  • Provide a migration reference for keylime_tenant and keylimectl command forms.
tenant_keylimectl_migration.txt

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Comment thread Library/test-helpers/lib.sh Fixed
Comment thread functional/basic-attestation-with-ima-signatures/test.sh Fixed

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 3 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="Library/test-helpers/lib.sh" line_range="1008-1010" />
<code_context>
+    esac
+
+    case "$_subcmd" in
+        agent)         __limeCtlAgent        "$@" ;;
+        policy)        __limeCtlPolicy       "$@" ;;
+        measured-boot) __limeCtlMeasuredBoot "$@" ;;
+        *)
+            echo "limeCtl: unknown subcommand '$_subcmd'" >&2
+            __limeCtlKtGlobal=()
+            return 1
+            ;;
+    esac
+    __limeCtlKtGlobal=()
+}
+
+__limeCtlAgent() {
</code_context>
<issue_to_address>
**issue (bug_risk):** The default `keylime_tenant` backend's exit status is discarded because `__limeCtlKtGlobal=()` runs after the handler and becomes the function's final command. `limeCtl` therefore returns success even when agent, policy, or measured-boot operations fail, causing `rlRun ... 1` checks and callers that depend on failure propagation to behave incorrectly.

**Triggers:** When `limeKeylimeTenant` returns nonzero while `limeCtlCommand` is unset or set to `keylime_tenant`.

**Suggested fix:** Save the handler status, clear `__limeCtlKtGlobal`, and return the saved status.

```suggestion
    esac
    local _status=$?
    __limeCtlKtGlobal=()
    return "$_status"
}
```
</issue_to_address>

### Comment 2
<location path="Library/test-helpers/lib.sh" line_range="956-959" />
<code_context>
+
+    while [ $# -gt 0 ]; do
+        case "$1" in
+            --verifier-ip)    _vip="$2";   shift 2 ;;
+            --registrar-ip)   _rip="$2";   shift 2 ;;
+            --verifier-port)  _vport="$2"; shift 2 ;;
+            --registrar-port) _rport="$2"; shift 2 ;;
+            -*)
+                echo "limeCtl: unknown option '$1'" >&2
</code_context>
<issue_to_address>
**issue (bug_risk):** `--verifier-port` and `--registrar-port` are parsed and retained in `_vport` and `_rport`, but the default `keylime_tenant` translation only appends `-v` and `-r` for the IP values. The port options are silently ignored whenever the wrapper uses the default backend.

**Triggers:** When a caller uses `limeCtl --verifier-port` or `limeCtl --registrar-port` with `limeCtlCommand=keylime_tenant`, especially against non-default service ports.

**Suggested fix:** Translate the port values into the keylime_tenant arguments/configuration format, or reject them explicitly for the backend that cannot honor them.
</issue_to_address>

### Comment 3
<location path="Library/test-helpers/lib.sh" line_range="976-984" />
<code_context>
+    [ -n "$_rip" ]   && __limeCtlKtGlobal+=(-r "$_rip")
+
+    case "$cmd" in
+        keylimectl)
+            case "$_subcmd" in
+                *)
+                    local _g=()
+                    [ -n "$_vip" ]   && _g+=(--verifier-ip "$_vip")
+                    [ -n "$_rip" ]   && _g+=(--registrar-ip "$_rip")
+                    [ -n "$_vport" ] && _g+=(--verifier-port "$_vport")
+                    [ -n "$_rport" ] && _g+=(--registrar-port "$_rport")
+                    keylimectl "${_g[@]}" "$_subcmd" "$@"
+                    __limeCtlKtGlobal=()
+                    return
</code_context>
<issue_to_address>
**issue (bug_risk):** With `limeCtlCommand=keylimectl`, every subcommand, including `registrar`, is passed directly to `keylimectl` because the inner case has only a wildcard branch. `keylimectl` has no registrar management commands, so a `limeCtl registrar ...` call fails instead of falling through to `limeKeylimeTenant` as required by the wrapper's migration behavior.

**Triggers:** When a caller uses the documented backend switch and invokes a registrar operation through `limeCtl`.

**Suggested fix:** Handle `registrar` before the keylimectl pass-through and dispatch it to the keylime_tenant registrar implementation.
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 3 findings to address first, and a bad option translation could enroll or update an agent with the wrong attestation, measured-boot, or runtime policy, or remove it from the verifier; those verifier-side changes persist after the wrapper is reverted and require cleanup or re-enrollment. The broad migration also makes failures possible across many tests, although the impact appears bounded to the environments running these test helpers rather than production.

Blocking findings: Library/test-helpers/lib.sh:1010, Library/test-helpers/lib.sh:959, Library/test-helpers/lib.sh:984


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread Library/test-helpers/lib.sh
Comment thread Library/test-helpers/lib.sh
Comment thread Library/test-helpers/lib.sh Outdated
Comment on lines +976 to +984
keylimectl)
case "$_subcmd" in
*)
local _g=()
[ -n "$_vip" ] && _g+=(--verifier-ip "$_vip")
[ -n "$_rip" ] && _g+=(--registrar-ip "$_rip")
[ -n "$_vport" ] && _g+=(--verifier-port "$_vport")
[ -n "$_rport" ] && _g+=(--registrar-port "$_rport")
keylimectl "${_g[@]}" "$_subcmd" "$@"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): With limeCtlCommand=keylimectl, every subcommand, including registrar, is passed directly to keylimectl because the inner case has only a wildcard branch. keylimectl has no registrar management commands, so a limeCtl registrar ... call fails instead of falling through to limeKeylimeTenant as required by the wrapper's migration behavior.

Triggers: When a caller uses the documented backend switch and invokes a registrar operation through limeCtl.

Suggested fix: Handle registrar before the keylimectl pass-through and dispatch it to the keylime_tenant registrar implementation.

@kkaarreell

Copy link
Copy Markdown
Collaborator Author

FTR, tests with limeCtl=keylime_tenant has passed. I will now redirect it to the keylimectl command.

Comment thread Library/test-helpers/lib.sh Outdated
Comment thread functional/basic-attestation-with-ima-signatures/test.sh Fixed
rlRun -s "keylime_tenant -c cvlist"
rlAssertGrep "{'code': 200, 'status': 'Success', 'results': {'uuids':.*'$AGENT_ID'" $rlRun_LOG -E
rlRun -s "limeCtl agent list"
rlRun "limeAssertJsonField $rlRun_LOG code=200 status=Success uuids=$AGENT_ID"
rlRun -s "keylime_tenant -c cvlist"
rlAssertGrep "{'code': 200, 'status': 'Success', 'results': {'uuids':.*'$AGENT_ID'" $rlRun_LOG -E
rlRun -s "limeCtl agent list"
rlRun "limeAssertJsonField $rlRun_LOG code=200 status=Success uuids=$AGENT_ID"
rlRun -s "keylime_tenant -c cvlist"
rlAssertGrep "{'code': 200, 'status': 'Success', 'results': {'uuids':.*'$AGENT_ID'" $rlRun_LOG -E
rlRun -s "limeCtl agent list"
rlRun "limeAssertJsonField $rlRun_LOG code=200 status=Success uuids=$AGENT_ID"
rlRun -s "keylime_tenant -c cvlist"
rlAssertGrep "{'code': 200, 'status': 'Success', 'results': {'uuids':.*'$AGENT_ID'" $rlRun_LOG -E
rlRun -s "limeCtl agent list"
rlRun "limeAssertJsonField $rlRun_LOG code=200 status=Success uuids=$AGENT_ID"
rlRun -s "keylime_tenant -c cvlist"
rlAssertGrep "{'code': 200, 'status': 'Success', 'results': {'uuids':.*'$AGENT_ID'" $rlRun_LOG -E
rlRun -s "limeCtl agent list"
rlRun "limeAssertJsonField $rlRun_LOG code=200 status=Success uuids=$AGENT_ID"
rlRun -s "keylime_tenant -c cvlist"
rlAssertGrep "{'code': 200, 'status': 'Success', 'results': {'uuids':.*'${AGENT_ID}'" $rlRun_LOG -E
rlRun -s "limeCtl agent list"
rlRun "limeAssertJsonField $rlRun_LOG code=200 status=Success uuids=${AGENT_ID}"
Comment thread regression/CVE-2023-3674/test.sh Outdated
rlRun -s "keylime_tenant -c cvlist"
rlAssertGrep "{'code': 200, 'status': 'Success', 'results': {'uuids':.*'$AGENT_ID'" "$rlRun_LOG" -E
rlRun -s "limeCtl agent list"
rlRun "limeAssertJsonField $rlRun_LOG code=200 status=Success uuids=$AGENT_ID"
Comment thread regression/cve-2023-38200/test.sh Outdated
rlRun -s "keylime_tenant -c cvlist"
rlAssertGrep "{'code': 200, 'status': 'Success', 'results': {'uuids':.*'$AGENT_ID'" $rlRun_LOG -E
rlRun -s "limeCtl agent list"
rlRun "limeAssertJsonField $rlRun_LOG code=200 status=Success uuids=$AGENT_ID"
rlRun "keylime_tenant -v 127.0.0.1 -t 127.0.0.1 -u $AGENT_ID -c delete"
rlRun "keylime_tenant -v 127.0.0.1 -t 127.0.0.1 -u $AGENT_ID --verify --runtime-policy policy.json --file /etc/hostname -c add"
rlRun -s "limeCtl agent list"
rlRun "limeAssertJsonField $rlRun_LOG code=200 status=Success uuids=$AGENT_ID"
rlRun -s "keylime_tenant -c cvlist"
rlAssertGrep "{'code': 200, 'status': 'Success', 'results': {'uuids':.*'$AGENT_ID'" $rlRun_LOG -E
rlRun -s "limeCtl agent list"
rlRun "limeAssertJsonField $rlRun_LOG code=200 status=Success uuids=$AGENT_ID"
Comment thread functional/basic-attestation-with-ima-signatures/test.sh Fixed
for I in `seq $TIMEOUT`; do
limeTimeoutCommand $TIMEOUT "limeKeylimeTenant -c status -u $UUID" &> $OUTPUT
AGTSTATE=$(cat "$OUTPUT" | grep "^{" | tail -1 | jq -r ".[].${FIELD}")
limeTimeoutCommand $TIMEOUT "limeCtl agent status $UUID --verifier" &> $OUTPUT
Introduce limeCtl() as a unified tenant management function whose
argument style mirrors keylimectl CLI. When limeCtlCommand=keylimectl
it passes calls straight through; the default keylime_tenant backend
translates each subcommand to equivalent keylime_tenant flags.

This also:
- Migrates all test scripts from keylime_tenant to limeCtl calls
- Adds limeAssertJsonField for JSON output validation
- Replaces rlAssertGrep JSON checks with limeAssertJsonField
- Switches status checks from operational_state to attestation_status
- Extends limeUpdateConf to support keylimectl TOML config
- Adjusts agent setup to build keylimectl
- Adds keylimectl migration documentation and help dump
@ansasaki

ansasaki commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

/packit test

Introduce limePolicy wrapper that uses keylimectl policy syntax as the
canonical interface and translates to keylime-policy when $limeCtlCommand
is set to keylime_tenant (default). Migrate all non-dedicated test usages
of keylime-policy to use the wrapper with long options to avoid short-flag
collisions between the two tools.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
kkaarreell and others added 2 commits September 4, 2026 17:01
Explicitly back up /etc/keylime/keylimectl.conf so it is properly
restored during test cleanup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The generic limeUpdateConf code path writes unquoted values to all
*.conf files in /etc/keylime. Since keylimectl.conf uses TOML format,
unquoted string values (e.g. mode = push) cause keylimectl to fail
with "invalid TOML value" parse errors. Exclude keylimectl.conf and
keylimectl.conf.d/ from the generic find — these files are already
handled by the dedicated TOML-aware "keylimectl" prefix path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
FILES="$( find ${CONF_DIR} -name '*.conf' )"
# Exclude keylimectl config files — they use TOML format and are handled
# by the "keylimectl" prefix path above.
FILES="$( find ${CONF_DIR} -name '*.conf' ! -name 'keylimectl.conf' ! -path '*/keylimectl.conf.d/*' )"
kkaarreell and others added 4 commits September 7, 2026 10:32
The sed range '/^{/,/^}/p' never terminates for single-line JSON
because the closing } is on the same line that starts with {.  This
caused sed to capture everything to EOF, feeding log messages to jq
which failed with "Invalid numeric literal".

Branch on limeCtlCommand: keylime_tenant uses grep "^{" | tail -1
(the proven single-line approach), keylimectl keeps the sed range
for pretty-printed multi-line JSON.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
keylime_tenant agent list output only contains the inner results JSON
(e.g. {"uuids": [...]}) without the code/status wrapper that keylimectl
includes. Assert only on uuids which is the meaningful field present in
both backends.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
keylime_tenant requires a payload (-k, -f, or --cert) when --verify
is used. These limeCtl calls had no payload, causing failures.
The --verify flag remains covered by direct keylime_tenant tests
that do provide payloads.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ansasaki

Copy link
Copy Markdown
Contributor

/packit test

1 similar comment
@ansasaki

Copy link
Copy Markdown
Contributor

/packit test

rlRun "limeWaitForAgentRegistration ${AGENT_ID}"
# create allowlist and excludelist
limeCreateTestPolicy
rlRun "limePolicy generate runtime --base-policy policy.json --add-ima-signature-verification-key ${limeIMAPublicKey} --output policy-with-keys.json"
kkaarreell and others added 3 commits September 17, 2026 15:06
The --ima-key argument is not available in keylimectl. Instead, embed
IMA signature verification keys directly into the runtime policy using
limePolicy generate runtime --base-policy --add-ima-signature-verification-key.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The --mb-refstate argument is not supported by keylimectl agent add.
Use --mb-policy instead to pass measured boot policy files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ansasaki

Copy link
Copy Markdown
Contributor

/packit test

2 similar comments
@ansasaki

Copy link
Copy Markdown
Contributor

/packit test

@ansasaki

Copy link
Copy Markdown
Contributor

/packit test

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.

3 participants