Skip to content

AAP-68113 [PENDING] Candle pin v2#363

Open
cshiels-ie wants to merge 22 commits intoansible:develfrom
cshiels-ie:candle-pin-v2
Open

AAP-68113 [PENDING] Candle pin v2#363
cshiels-ie wants to merge 22 commits intoansible:develfrom
cshiels-ie:candle-pin-v2

Conversation

@cshiels-ie
Copy link
Copy Markdown
Contributor

@cshiels-ie cshiels-ie commented Apr 1, 2026

Candlepin Integration

Overview

This branch adds Candlepin consumer identity certificate support to metrics-utility, enabling AAP controller instances to authenticate analytics uploads to console.redhat.com using mTLS instead of a service account. The certificate is stored in the AWX conf_setting database table, making the solution topology-agnostic across RPM and containerised deployments.

When a valid Candlepin certificate is present the upload path switches to mTLS automatically. If the certificate is absent, expired, or the TLS handshake fails, the system falls back to service-account authentication so existing deployments are never broken.


New modules

metrics_utility/library/candlepin/client.pyCandlepinClient

Thin REST client for the Candlepin API. All API calls that require authentication after initial registration use the consumer identity certificate (mTLS), matching the pattern used by subscription-manager.

Method Endpoint Auth Purpose
register_consumer POST /consumers?owner={org} Basic (username/password) Register this AAP instance and obtain an identity certificate
checkin PUT /consumers/{uuid} mTLS Reset the inactivity timer; best-effort, never raises
regenerate_cert POST /consumers/{uuid} mTLS Force certificate renewal; raises RuntimeError on failure

TLS verification defaults to True (system CA store). Pass candlepin_ca to verify against a specific CA bundle (e.g. /etc/rhsm/ca/redhat-uep.pem). Verification can only be disabled by explicitly passing verify_tls=False; a warning is logged when this branch is reached.

Proxy support: the supplied proxy URL is used as-is for the https key and normalised to http:// for the http key, so plain-HTTP proxies with CONNECT tunnelling work correctly.

Temporary PEM files written to disk for mTLS calls are created with 0o600 permissions and unconditionally deleted on context-manager exit, even on exception.

metrics_utility/library/candlepin/lifecycle.py

Certificate inspection and lifecycle orchestration helpers.

Function Purpose
parse_cert(pem_text) Parse a PEM cert; return serial, CN, expiry, days remaining, etc.
is_cert_valid(cert_pem) Guard check: parseable, not-yet-valid, not-expired. Returns False and logs a warning on any failure so callers fall back to service-account auth.
needs_renewal(pem_text, days_before_expiry) True if the cert expires within the threshold (or is already expired).
run_candlepin_lifecycle(...) Orchestrate one gather-run lifecycle: inspect cert → check-in → proactive renewal if needed. Returns (cert_pem, key_pem) — original or renewed.

Config helpers (get_candlepin_url, get_renewal_days, get_candlepin_ca) read from environment variables with sensible defaults.


Changes to existing code

metrics_utility/management/validation.py

New functions and constants added to handle_crc_ship_target and the surrounding helpers.

Constants

CANDLEPIN_CERT_SETTING_KEY = 'CANDLEPIN_CONSUMER_CERT'
CANDLEPIN_KEY_SETTING_KEY  = 'CANDLEPIN_CONSUMER_KEY'
CANDLEPIN_UUID_SETTING_KEY = 'CANDLEPIN_CONSUMER_UUID'
CANDLEPIN_UUID_PLACEHOLDER = '00000000-0000-0000-0000-000000000000'

SUBSCRIPTIONS_USERNAME_SETTING_KEY = 'SUBSCRIPTIONS_USERNAME'
SUBSCRIPTIONS_PASSWORD_SETTING_KEY = 'SUBSCRIPTIONS_PASSWORD'

Registration flow (METRICS_UTILITY_CANDLEPIN_REGISTRATION_ENABLED)

_fetch_registration_credentials_from_db() reads SUBSCRIPTIONS_USERNAME, SUBSCRIPTIONS_PASSWORD (set by AWX when the customer configures their Red Hat subscription), and LICENSE.account_number (the Candlepin org key) from conf_setting in a single query.

_register_candlepin_consumer() calls CandlepinClient.register_consumer with those credentials and persists the result via _save_candlepin_registration_to_db, which UPSERTs the cert PEM, key PEM, and consumer UUID to conf_setting in a single transaction.

Lifecycle flow (METRICS_UTILITY_CANDLEPIN_LIFECYCLE_ENABLED)

_fetch_candlepin_lifecycle_from_db() reads the stored cert, key, and consumer UUID.

_run_candlepin_lifecycle() calls run_candlepin_lifecycle from the library module. If the cert is renewed, _save_candlepin_cert_to_db UPSERTs the updated cert and key back to conf_setting.

handle_crc_ship_target execution order

  1. Read cert/key/UUID from conf_setting.
  2. If no cert and METRICS_UTILITY_CANDLEPIN_REGISTRATION_ENABLED is set → attempt registration.
  3. If cert now available and METRICS_UTILITY_CANDLEPIN_LIFECYCLE_ENABLED is set → check-in + proactive renewal.
  4. Inject candlepin_cert_pem / candlepin_key_pem into billing_provider_params for the upload step.

All steps are best-effort: failures log a warning or error and fall through to service-account auth.

metrics_utility/automation_controller_billing/package/package_crc.py

  • shipping_auth_mode() now returns SHIPPING_AUTH_CERTIFICATES when a valid Candlepin cert is available, SHIPPING_AUTH_SERVICE_ACCOUNT otherwise. The result is cached in _resolved_auth_mode.
  • ship() overridden to manage the temp-file lifecycle for mTLS uploads via CandlepinClient._temp_cert_files. On SSLError, falls back to service-account auth if those credentials are configured; raises FailedToUploadPayload if not, so the operator gets an actionable error.
  • _send_data() gains a SHIPPING_AUTH_CERTIFICATES branch that posts with session.cert and server-cert verification.
  • _gather_config() strips candlepin_cert_pem and candlepin_key_pem from the billing_provider_params dict before writing it to the config.json payload archive, preventing key material from being uploaded to the ingress endpoint.

New CLI command

uv run ./manage.py candlepin_manage

subcommands:
  register   Register this instance as a Candlepin consumer
  renew      Check in and renew the Candlepin identity certificate

candlepin_manage register

Registers this AAP instance with Candlepin and stores the resulting identity certificate, key, and consumer UUID in conf_setting.

Credentials are read from AWX conf_setting by default (SUBSCRIPTIONS_USERNAME, SUBSCRIPTIONS_PASSWORD, LICENSE.account_number). CLI flags override the DB values.

--username    Red Hat subscription username
--password    Red Hat subscription password
--org         Candlepin owner/org key
--candlepin-url   Override METRICS_UTILITY_CANDLEPIN_URL
--candlepin-ca    Path to Candlepin CA cert for TLS verification
--proxy       Override METRICS_UTILITY_PROXY_URL
--force       Re-register even if a certificate already exists
--dry-run     Perform registration but do not save to conf_setting

candlepin_manage renew

Reads the stored cert/key/UUID from conf_setting, performs a check-in, and renews the certificate if it is within the renewal window (default: 30 days).

--candlepin-url   Override METRICS_UTILITY_CANDLEPIN_URL
--candlepin-ca    Path to Candlepin CA cert for TLS verification
--proxy       Override METRICS_UTILITY_PROXY_URL
--force       Renew even if the cert is not near expiry
--dry-run     Perform check-in and renewal but do not save to conf_setting

New environment variables

Variable Default Purpose
METRICS_UTILITY_CANDLEPIN_URL https://subscription.rhsm.redhat.com/subscription Candlepin base URL
METRICS_UTILITY_CANDLEPIN_CA (none — system CA store) Path to Candlepin CA cert for TLS verification
METRICS_UTILITY_CANDLEPIN_RENEWAL_DAYS 30 Days before expiry at which proactive renewal is triggered
METRICS_UTILITY_CANDLEPIN_REGISTRATION_ENABLED (unset / false) Enable automatic consumer registration on gather runs
METRICS_UTILITY_CANDLEPIN_LIFECYCLE_ENABLED (unset / false) Enable check-in and proactive renewal on gather runs

Database storage

All Candlepin material is stored in the existing AWX conf_setting table using the standard UPSERT pattern already used by the rest of the codebase. No schema changes are required.

Key Content
CANDLEPIN_CONSUMER_CERT Consumer identity certificate PEM
CANDLEPIN_CONSUMER_KEY Consumer identity private key PEM
CANDLEPIN_CONSUMER_UUID Candlepin consumer UUID

The AWX DB seed (tools/docker/conf_setting.sql) seeds CANDLEPIN_CONSUMER_UUID with the all-zeros placeholder. The placeholder is treated the same as an absent value — no lifecycle or registration calls are made until a real UUID is written.


Dependencies

cryptography>=42.0.0 added to pyproject.toml for X.509 certificate parsing.


Test coverage

Test file What is covered
test/library/test_candlepin_client.py CandlepinClient: construction, temp-file lifecycle, checkin, regenerate_cert, register_consumer
test/library/test_candlepin_lifecycle.py parse_cert, is_cert_valid, needs_renewal, run_candlepin_lifecycle
test/gather/test_package_crc.py PackageCRC: auth-mode selection, mTLS ship path, SSL fallback, temp-file cleanup
test/validation/test_candlepin_validation.py DB fetch/save helpers, _run_candlepin_lifecycle, _register_candlepin_consumer, handle_crc_ship_target integration
test/management/commands/test_candlepin_manage.py candlepin_manage register and renew subcommands

Note

High Risk
Touches analytics upload authentication and introduces certificate/key handling plus direct DB read/write of sensitive material, so misconfiguration or edge cases could break shipping or leak credentials if incorrect. Broad new surface area (Candlepin API calls, lifecycle automation, CLI) increases operational risk despite test coverage.

Overview
Adds Candlepin consumer identity certificate support so CRC billing uploads can authenticate via mTLS when a valid cert/key is available, with automatic fallback to service-account auth on invalid/expired certs or TLS handshake failures.

Introduces a new metrics_utility.library.candlepin client + lifecycle helpers, wires them into handle_crc_ship_target() to optionally auto-register consumers and proactively check-in/renew certs using values stored in conf_setting, and adds a candlepin_manage management command to register/renew manually.

Hardens security by stripping candlepin_cert_pem/candlepin_key_pem from the archived config.json payload, uses secure temp files for mTLS keys during shipping, and adds cryptography plus extensive unit tests/seed updates for Candlepin settings.

Reviewed by Cursor Bugbot for commit 58c971d. Bugbot is set up for automated code reviews on this repo. Configure here.

cshiels-ie and others added 7 commits March 31, 2026 11:18
- Added `cryptography` dependency to `pyproject.toml` and `uv.lock`.
- Enhanced `PackageCRC` class to support mTLS authentication using Candlepin certificates.
- Implemented methods to fetch certificates from the database and validate them.
- Updated shipping logic to handle both mTLS and service account authentication modes.
- Added logging for certificate loading and validation processes.
…ve tests

- Updated the `is_shipping_configured` method in the `PackageCRC` class to correctly call the superclass method.
- Introduced a new test suite for `PackageCRC`, including tests for certificate validation and shipping configuration logic.
- Added tests to ensure proper behavior when certificates are valid, expired, or missing, as well as when the shipping configuration is checked under various conditions.
- Updated the `Collector` class to exclude sensitive billing keys from the configuration collection.
- Improved error handling in the `PackageCRC` class to raise a `FailedToUploadPayload` exception when mTLS fails and no service account credentials are available.
- Added tests to ensure proper behavior when service account credentials are missing or present during SSL errors.
- Introduced a new method `_cleanup_temp_pem_files` in the `PackageCRC` class to handle the closing of file descriptors and deletion of temporary PEM files.
- Replaced the previous inline cleanup logic in the `ship` method with a call to the new cleanup method, enhancing maintainability and clarity.
- Introduced `CandlepinClient` for interacting with the Candlepin API, including methods for check-in and certificate regeneration.
- Added lifecycle management functions to handle certificate parsing, renewal checks, and orchestration of check-in and renewal processes.
- Implemented database functions to fetch and save Candlepin certificate data.
- Created unit tests for the `CandlepinClient` and lifecycle management functions to ensure proper functionality and error handling.
- Updated validation logic to integrate Candlepin lifecycle management into the existing workflow.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 1, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • ✅ Review completed - (🔄 Check again to review again)
📝 Walkthrough

Walkthrough

Adds Candlepin mTLS support: a Candlepin REST client, certificate parsing/lifecycle and renewal, mTLS-capable CRC shipping with temporary cert files and auth-mode resolution, DB wiring for cert storage/registration, billing-param sanitization, tests, and a cryptography runtime dependency.

Changes

Cohort / File(s) Summary
Candlepin client & lifecycle
metrics_utility/library/candlepin/client.py, metrics_utility/library/candlepin/lifecycle.py
Adds CandlepinClient (register_consumer, checkin, regenerate_cert) with secure temp PEM handling, plus lifecycle utilities: cert parsing, validity checks, renewal decision, run_candlepin_lifecycle, and env-backed helpers.
Package CRC mTLS support
metrics_utility/automation_controller_billing/package/package_crc.py
Extends PackageCRC: adds __init__ fields, cached auth-mode resolution, _get_client_certificates(), mTLS-aware ship() and _send_data() branches, temp cert file lifecycle, and SSLError handling with optional fallback to service-account auth.
Validation, DB wiring & collector sanitization
metrics_utility/management/validation.py, metrics_utility/automation_controller_billing/collector.py
Sanitizes billing_provider_params before persisting (filters Candlepin cert/key). Adds DB helpers to fetch/save Candlepin certs/UUID, registration flow, lifecycle orchestration gated by env flags, and injection of cert PEMs into billing params when available.
Tests
metrics_utility/test/gather/test_package_crc.py, metrics_utility/test/library/test_candlepin_client.py, metrics_utility/test/library/test_candlepin_lifecycle.py, metrics_utility/test/validation/test_candlepin_validation.py
Adds extensive unit tests covering Candlepin client, lifecycle logic, PackageCRC auth-mode/config checks and ship behavior, DB fetch/save helpers, lifecycle orchestration, temp-file permissions/cleanup, SSL-error handling, and env-driven scenarios.
Config & packaging
pyproject.toml, tools/docker/conf_setting.sql, sonar-project.properties
Adds cryptography>=42.0.0 dependency, seeds CANDLEPIN_CONSUMER_UUID placeholder in SQL fixture, and tweaks SonarQube test exclusion pattern.

Sequence Diagram(s)

sequenceDiagram
    participant CRC as PackageCRC
    participant Validation as Validation Handler
    participant DB as Database
    participant Client as CandlepinClient
    participant Candlepin as Candlepin Server

    CRC->>Validation: handle_crc_ship_target(params)
    Validation->>DB: SELECT conf_setting for cert/key/uuid
    DB-->>Validation: cert_pem, key_pem, consumer_uuid

    alt cert present
        Validation->>Validation: parse_cert() / is_cert_valid()
        Validation->>Client: checkin(consumer_uuid, cert_pem, key_pem)
        Client->>Candlepin: PUT /consumers/{uuid} (mTLS via temp cert files)
        Candlepin-->>Client: 200/204
        Client-->>Validation: success

        alt needs renewal
            Validation->>Client: regenerate_cert(consumer_uuid, cert_pem, key_pem)
            Client->>Candlepin: POST /consumers/{uuid} (mTLS)
            Candlepin-->>Client: {idCert: {cert, key}}
            Client-->>Validation: new_cert_pem, new_key_pem
            Validation->>DB: UPSERT new cert/key
        end

        Validation-->>CRC: billing_params w/ candlepin_cert_pem/key_pem
    else no cert
        Validation-->>CRC: billing_params (service-account mode)
    end

    CRC->>CRC: PackageCRC.ship() chooses auth mode (certs or service-account) and posts payload
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is vague and uses non-descriptive phrasing like 'Candle pin v2' that doesn't convey the main change (Candlepin-backed mTLS support for CRC uploads). Revise the title to clearly describe the primary change, e.g., 'Add Candlepin-backed mTLS support for CRC payload uploads' or 'Implement mTLS certificate lifecycle for Candlepin consumer identity'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed PR description is comprehensive with clear structure covering overview, new modules, changes to existing code, new CLI command, environment variables, database storage, dependencies, and test coverage.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

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

…rtificate management

- Replaced inline temporary file handling in the `ship` method with a context manager from `CandlepinClient` for improved clarity and resource management.
- Introduced a new `is_cert_valid` function in the Candlepin lifecycle module to streamline certificate validation and logging.
- Updated tests to reflect changes in certificate validation logic and ensure proper logging behavior for expired or invalid certificates.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (4)
metrics_utility/test/library/test_candlepin_client.py (1)

114-118: Unused parameters in test method signature.

The cert_pem and key_pem parameters have default values of None but are immediately overwritten by _generate_cert_and_key(). These parameters appear to be leftover from refactoring.

♻️ Suggested fix
-    def test_files_have_mode_0600(self, cert_pem=None, key_pem=None):
+    def test_files_have_mode_0600(self):
         cert_pem, key_pem = _generate_cert_and_key()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@metrics_utility/test/library/test_candlepin_client.py` around lines 114 -
118, The test method test_files_have_mode_0600 declares unused parameters
cert_pem and key_pem which are immediately overwritten by
_generate_cert_and_key(); remove the parameters from the signature so it becomes
def test_files_have_mode_0600(self):, leaving the body unchanged (it still calls
_generate_cert_and_key() and uses CandlepinClient._temp_cert_files to check file
modes); run the test suite to ensure no other tests or fixtures depend on those
parameters and adjust any callers if necessary.
metrics_utility/management/validation.py (1)

257-296: Consider adding explicit placeholder UUID detection.

The if not consumer_uuid: check at line 267 is a truthiness check that will pass for any non-empty string. If the Docker dev seed inserts a placeholder UUID like "00000000-0000-0000-0000-000000000000", this will incorrectly trigger lifecycle operations. Consider an explicit check:

🛡️ Suggested fix
+PLACEHOLDER_UUID = '00000000-0000-0000-0000-000000000000'
+
 def _run_candlepin_lifecycle(cert_pem, key_pem, consumer_uuid):
-    if not consumer_uuid:
+    if not consumer_uuid or consumer_uuid == PLACEHOLDER_UUID:
         logger.warning(
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@metrics_utility/management/validation.py` around lines 257 - 296, The
truthiness check in _run_candlepin_lifecycle for consumer_uuid allows
placeholder UUIDs (e.g. "00000000-0000-0000-0000-000000000000") to proceed;
update the guard to explicitly detect and skip placeholder values as well as
empty/falsy ones by checking consumer_uuid against the known placeholder string
(and/or any other configured sentinel) before proceeding with
run_candlepin_lifecycle, and keep the existing warning message when skipping;
reference consumer_uuid, _run_candlepin_lifecycle, and CANDLEPIN_CONSUMER_UUID
when making the change.
metrics_utility/test/validation/test_candlepin_validation.py (1)

119-202: Consider adding test coverage for lifecycle-enabled path.

The tests cover credential injection and logging well, but don't exercise the METRICS_UTILITY_CANDLEPIN_LIFECYCLE_ENABLED branch in handle_crc_ship_target. Consider adding a test that enables the flag and mocks _run_candlepin_lifecycle to verify the integration.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@metrics_utility/test/validation/test_candlepin_validation.py` around lines
119 - 202, Tests are missing coverage for the
METRICS_UTILITY_CANDLEPIN_LIFECYCLE_ENABLED branch in handle_crc_ship_target;
add a test in TestHandleCrcShipTargetCandlepin that sets
monkeypatch.setenv('METRICS_UTILITY_CANDLEPIN_LIFECYCLE_ENABLED','true'),
patches django.db.connection.cursor as needed, and patches/Mocks
metrics_utility.management.validation._run_candlepin_lifecycle to assert it is
called with the expected params (and/or to return a controlled value), and also
assert existing behavior (e.g., billing fields still present and cert
injection/logging behavior) to verify integration.
metrics_utility/library/candlepin/lifecycle.py (1)

42-43: Avoid accessing private _name attribute; use public API instead.

attr.oid._name is an internal attribute explicitly excluded from the public API (cryptography PR #5852 rejected making it public). The current code risks breakage in future versions. For this use case, either use a static OID-to-name mapping or switch to dotted_string (public API, though less human-readable).

♻️ Suggested alternative
from cryptography.x509.oid import NameOID

# Map known OIDs to friendly names (public API safe)
OID_NAME_MAP = {
    NameOID.COMMON_NAME: 'commonName',
    NameOID.ORGANIZATION_NAME: 'organizationName',
    # Add additional OIDs as needed
}

subject = {OID_NAME_MAP.get(attr.oid, attr.oid.dotted_string): attr.value for attr in cert.subject}
issuer = {OID_NAME_MAP.get(attr.oid, attr.oid.dotted_string): attr.value for attr in cert.issuer}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@metrics_utility/library/candlepin/lifecycle.py` around lines 42 - 43, Replace
the private attr.oid._name usage in the subject/issuer comprehensions with a
public API approach: use attr.oid.dotted_string as the fallback and optionally
map known cryptography.x509.oid.NameOID constants to friendly names (e.g., map
NameOID.COMMON_NAME -> "commonName") before building the dicts; update the
comprehensions that construct subject and issuer (which iterate cert.subject and
cert.issuer and reference attr and attr.oid) to consult the
OID_NAME_MAP.get(attr.oid, attr.oid.dotted_string) instead of attr.oid._name so
the code uses public attributes and avoids private internals.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@metrics_utility/automation_controller_billing/package/package_crc.py`:
- Around line 19-29: The current _is_cert_valid(cert_pem: str) only checks parse
success and not_valid_after_utc; extend validation so shipping_auth_mode() will
not choose SHIPPING_AUTH_CERTIFICATES for unusable creds: update _is_cert_valid
to also check cert.not_valid_before_utc <= now (UTC) to reject not-yet-valid
certs, parse and load the corresponding private key (use the same PEM key input
used by shipping_auth_mode / the key field) to ensure it is a valid private key,
and verify the private key matches the certificate's public key (e.g., by
comparing public key parameters) before returning True; ensure
shipping_auth_mode's path that currently only checks non-empty key also calls
this enhanced _is_cert_valid and refrains from selecting
SHIPPING_AUTH_CERTIFICATES if any of these checks fail so cert/key mismatches,
malformed keys, or future-dated certs are rejected up front.
- Around line 118-132: The current ship() SSLError handler blindly retries the
POST and can duplicate uploads; change it to only retry when you can positively
detect a client-certificate rejection (inspect the SSLError exception
string/args for handshake/client-cert failure tokens such as
"CERTIFICATE_REQUIRED", "certificate", "handshake", "unknown ca", or similar)
and otherwise raise FailedToUploadPayload; if you cannot reliably detect such a
rejection, do not retry and instead raise the error. Use the same symbols shown
(_get_rh_user(), _get_rh_password(), _resolved_auth_mode,
SHIPPING_AUTH_SERVICE_ACCOUNT, _temp_cert_path/_temp_key_path and
super().ship()) to implement the conditional retry path, and if you must attempt
a retry ensure an idempotency guard is sent (e.g., set an Idempotency-Key
header) before calling super().ship() so the ingress cannot ingest duplicates.

In `@tools/docker/conf_setting.sql`:
- Around line 9-10: The seed data uses an all-zero UUID string which
deserializes to a non-empty Python string and bypasses the existing truthiness
check in validation.py; update the logic in _run_candlepin_lifecycle to
explicitly detect and treat the placeholder value
("00000000-0000-0000-0000-000000000000") as absent (i.e., skip the Candlepin
lifecycle) by checking consumer_uuid == "00000000-0000-0000-0000-000000000000"
or similar, or alternatively remove/replace the seed row with an actual empty
string (e.g., '""') so the existing if not consumer_uuid check works as
intended.

---

Nitpick comments:
In `@metrics_utility/library/candlepin/lifecycle.py`:
- Around line 42-43: Replace the private attr.oid._name usage in the
subject/issuer comprehensions with a public API approach: use
attr.oid.dotted_string as the fallback and optionally map known
cryptography.x509.oid.NameOID constants to friendly names (e.g., map
NameOID.COMMON_NAME -> "commonName") before building the dicts; update the
comprehensions that construct subject and issuer (which iterate cert.subject and
cert.issuer and reference attr and attr.oid) to consult the
OID_NAME_MAP.get(attr.oid, attr.oid.dotted_string) instead of attr.oid._name so
the code uses public attributes and avoids private internals.

In `@metrics_utility/management/validation.py`:
- Around line 257-296: The truthiness check in _run_candlepin_lifecycle for
consumer_uuid allows placeholder UUIDs (e.g.
"00000000-0000-0000-0000-000000000000") to proceed; update the guard to
explicitly detect and skip placeholder values as well as empty/falsy ones by
checking consumer_uuid against the known placeholder string (and/or any other
configured sentinel) before proceeding with run_candlepin_lifecycle, and keep
the existing warning message when skipping; reference consumer_uuid,
_run_candlepin_lifecycle, and CANDLEPIN_CONSUMER_UUID when making the change.

In `@metrics_utility/test/library/test_candlepin_client.py`:
- Around line 114-118: The test method test_files_have_mode_0600 declares unused
parameters cert_pem and key_pem which are immediately overwritten by
_generate_cert_and_key(); remove the parameters from the signature so it becomes
def test_files_have_mode_0600(self):, leaving the body unchanged (it still calls
_generate_cert_and_key() and uses CandlepinClient._temp_cert_files to check file
modes); run the test suite to ensure no other tests or fixtures depend on those
parameters and adjust any callers if necessary.

In `@metrics_utility/test/validation/test_candlepin_validation.py`:
- Around line 119-202: Tests are missing coverage for the
METRICS_UTILITY_CANDLEPIN_LIFECYCLE_ENABLED branch in handle_crc_ship_target;
add a test in TestHandleCrcShipTargetCandlepin that sets
monkeypatch.setenv('METRICS_UTILITY_CANDLEPIN_LIFECYCLE_ENABLED','true'),
patches django.db.connection.cursor as needed, and patches/Mocks
metrics_utility.management.validation._run_candlepin_lifecycle to assert it is
called with the expected params (and/or to return a controlled value), and also
assert existing behavior (e.g., billing fields still present and cert
injection/logging behavior) to verify integration.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: fe5b8deb-1f6d-4938-aaf5-3d59eb018c81

📥 Commits

Reviewing files that changed from the base of the PR and between a06338f and d4f1f07.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (12)
  • metrics_utility/automation_controller_billing/collector.py
  • metrics_utility/automation_controller_billing/package/package_crc.py
  • metrics_utility/library/candlepin/__init__.py
  • metrics_utility/library/candlepin/client.py
  • metrics_utility/library/candlepin/lifecycle.py
  • metrics_utility/management/validation.py
  • metrics_utility/test/gather/test_package_crc.py
  • metrics_utility/test/library/test_candlepin_client.py
  • metrics_utility/test/library/test_candlepin_lifecycle.py
  • metrics_utility/test/validation/test_candlepin_validation.py
  • pyproject.toml
  • tools/docker/conf_setting.sql

Comment thread metrics_utility/automation_controller_billing/package/package_crc.py Outdated
Comment thread metrics_utility/automation_controller_billing/package/package_crc.py Outdated
Comment thread tools/docker/conf_setting.sql
Comment thread metrics_utility/management/validation.py Outdated
Comment thread metrics_utility/management/validation.py Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@metrics_utility/library/candlepin/lifecycle.py`:
- Around line 58-73: The is_cert_valid function currently only checks
parse_cert(...) and info['days_remaining'] < 0; update it to also verify the
certificate is not yet valid by checking info['not_valid_before_utc'] (from
parse_cert) against the current UTC time: if current time is before
not_valid_before_utc, log a warning (similar to the expired-path) mentioning the
not_valid_before_utc and return False so callers fall back to service-account
auth; keep existing expired and parse error handling unchanged and use the same
logger and message style as the existing checks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: e042a952-a803-421b-bd18-0723c1e24bc7

📥 Commits

Reviewing files that changed from the base of the PR and between d4f1f07 and 9fb7955.

📒 Files selected for processing (3)
  • metrics_utility/automation_controller_billing/package/package_crc.py
  • metrics_utility/library/candlepin/lifecycle.py
  • metrics_utility/test/gather/test_package_crc.py
✅ Files skipped from review due to trivial changes (1)
  • metrics_utility/test/gather/test_package_crc.py

Comment thread metrics_utility/library/candlepin/lifecycle.py
- Updated `is_cert_valid` function to check for certificates that are not yet valid, in addition to expired and unparseable certificates, improving logging for operator visibility.
- Introduced a placeholder UUID constant to handle cases where a real consumer UUID is not registered, ensuring that lifecycle calls are skipped appropriately.
- Refactored database functions to use transactions for saving Candlepin certificate data, enhancing data integrity.
- Updated tests to reflect changes in lifecycle management, including handling of placeholder UUIDs and improved logging behavior.
Comment thread metrics_utility/management/validation.py Outdated
- Changed the proxy URL in the `test_proxy_set` method from HTTP to HTTPS, ensuring secure connections are tested.
- Updated the expected proxies dictionary to reflect the change in protocol.
Comment thread metrics_utility/test/library/test_candlepin_client.py
- Implemented the `register_consumer` method in `CandlepinClient` to register a new AAP consumer with the Candlepin API, utilizing Red Hat subscription credentials.
- Added helper functions to fetch registration credentials from the database and save the consumer registration details.
- Integrated the registration process into the validation logic, allowing for automatic consumer registration when no identity certificate exists.
- Enhanced unit tests for `CandlepinClient` and validation functions to cover the new registration functionality and ensure proper error handling.
- Updated the proxy configuration in the `CandlepinClient` constructor to normalize the proxy URL by stripping any existing scheme and prefixing it with the appropriate protocol.
- Ensured that the proxies dictionary is correctly set up for both HTTP and HTTPS connections, improving the handling of proxy settings.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
metrics_utility/test/validation/test_candlepin_validation.py (1)

264-270: Minor duplication with _make_cursor_with_rows helper.

The _make_cursor_rows helper is nearly identical to _make_cursor_with_rows defined earlier (lines 26-33). Consider consolidating into a single helper function.

♻️ Suggested consolidation
-def _make_cursor_rows(rows):
-    mock_cursor = MagicMock()
-    mock_cursor.fetchall.return_value = rows
-    mock_conn = MagicMock()
-    mock_conn.__enter__ = MagicMock(return_value=mock_cursor)
-    mock_conn.__exit__ = MagicMock(return_value=False)
-    return mock_conn

Then use _make_cursor_with_rows(rows)[0] or adjust the original helper to return just the connection when cursor isn't needed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@metrics_utility/test/validation/test_candlepin_validation.py` around lines
264 - 270, Consolidate the duplicate helpers by removing _make_cursor_rows and
reusing the existing _make_cursor_with_rows: either call
_make_cursor_with_rows(rows)[0] where the connection-only behavior is needed, or
modify _make_cursor_with_rows to optionally return just the mock connection
(e.g., via a parameter) and update call sites; replace all uses of
_make_cursor_rows with the chosen approach and delete the redundant function.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@metrics_utility/test/validation/test_candlepin_validation.py`:
- Around line 264-270: Consolidate the duplicate helpers by removing
_make_cursor_rows and reusing the existing _make_cursor_with_rows: either call
_make_cursor_with_rows(rows)[0] where the connection-only behavior is needed, or
modify _make_cursor_with_rows to optionally return just the mock connection
(e.g., via a parameter) and update call sites; replace all uses of
_make_cursor_rows with the chosen approach and delete the redundant function.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 97648ca7-212f-4a3d-9cf2-3325647a5a0d

📥 Commits

Reviewing files that changed from the base of the PR and between 9fb7955 and 5422145.

📒 Files selected for processing (5)
  • metrics_utility/library/candlepin/client.py
  • metrics_utility/library/candlepin/lifecycle.py
  • metrics_utility/management/validation.py
  • metrics_utility/test/library/test_candlepin_client.py
  • metrics_utility/test/validation/test_candlepin_validation.py
✅ Files skipped from review due to trivial changes (1)
  • metrics_utility/test/library/test_candlepin_client.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • metrics_utility/library/candlepin/lifecycle.py

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@metrics_utility/library/candlepin/client.py`:
- Around line 28-33: The proxy normalization currently strips the provided
scheme and forces per-protocol schemes which breaks HTTP CONNECT proxies; update
the logic in the client (the code that sets self.proxies in
metrics_utility/library/candlepin/client.py) to preserve an explicit scheme if
the user supplies one, otherwise default to "http://" and then assign the same
proxy URL for both 'http' and 'https' keys (i.e., do not create distinct
https/http schemes by reappending different prefixes); also update the test
assertion in test_candlepin_client.py (the test around lines 85-86) to expect
the same proxy URL for both protocols when a scheme is present or defaulted.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 687562c1-f58d-4cd3-9ada-bbf11ff74906

📥 Commits

Reviewing files that changed from the base of the PR and between 5422145 and dc81e78.

📒 Files selected for processing (1)
  • metrics_utility/library/candlepin/client.py

Comment thread metrics_utility/library/candlepin/client.py
Comment thread metrics_utility/library/candlepin/client.py Outdated
- Changed the coverage exclusions pattern from `metrics_utility/test/**` to `**/tests/**`, allowing for broader exclusion of test directories across the project.
Comment thread sonar-project.properties Outdated
- Introduced a constant for the default renewal days in the `lifecycle.py` module, improving code readability and maintainability.
- Updated the `get_renewal_days` function to use the new constant, ensuring consistent default values and clearer logging for invalid environment variable cases.
- Removed the redundant default value definition from the `validation.py` module, streamlining the codebase.
- Enhanced the proxy configuration logic in the `CandlepinClient` constructor to better handle HTTPS and HTTP proxy URLs.
- Updated comments for clarity on how the proxy URLs are processed, ensuring correct usage of the intended scheme for both HTTP and HTTPS connections.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
metrics_utility/library/candlepin/client.py (1)

28-37: ⚠️ Potential issue | 🟠 Major

Proxy handling still risks broken HTTPS tunneling behavior

Line 36 keeps different proxy values for https and http, and if proxy is passed without a scheme, the https value can remain scheme-less. This can break requests proxy resolution and standard CONNECT proxy usage.

Proposed fix
         if proxy:
-            # Use the caller-supplied URL as-is for HTTPS targets (preserves the
-            # intended scheme — usually http:// so requests uses plain HTTP to reach
-            # the proxy and issues CONNECT for TLS tunneling, but https:// is also
-            # accepted for the rare case of an HTTPS-fronted proxy).
-            # The http:// key always uses plain HTTP since non-TLS traffic never
-            # needs TLS to the proxy itself.
-            host = proxy.split('://', 1)[-1]
-            self.proxies = {'https': proxy, 'http': f'http://{host}'}
+            if '://' not in proxy:
+                proxy = f'http://{proxy}'
+            self.proxies = {'https': proxy, 'http': proxy}
#!/bin/bash
set -euo pipefail

# Verify current proxy normalization logic and related test expectations/docs.
rg -n -C3 'if proxy:|self\.proxies|split\(.:\/\/|METRICS_UTILITY_PROXY_URL|proxy' \
  metrics_utility/library/candlepin/client.py \
  metrics_utility/management/validation.py \
  metrics_utility/test/library/test_candlepin_client.py

As per coding guidelines, "Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@metrics_utility/library/candlepin/client.py` around lines 28 - 37, The proxy
handling may leave the 'https' proxy value without a scheme, breaking requests'
proxy resolution; update the normalization so any incoming proxy string missing
a scheme gets an explicit scheme (default to "http://"), then build self.proxies
using that normalized proxy for the 'https' key and an explicit "http://{host}"
for the 'http' key (use the normalized host computed from the normalized proxy);
adjust the code around the proxy variable, host extraction, and self.proxies
assignment to always supply scheme-qualified proxy URLs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@metrics_utility/library/candlepin/client.py`:
- Around line 25-27: The constructor currently sets self.verify = candlepin_ca
if candlepin_ca else False which makes TLS verification disabled by default;
change __init__ (referencing DEFAULT_CANDLEPIN_URL and self.verify) so verify
defaults to True when candlepin_ca is None (i.e., enable certificate
verification), and introduce an explicit opt-in flag (e.g., allow_insecure or
verify_tls=False parameter or env var check) that must be deliberately set to
disable verification; update register_consumer to continue using self.verify but
ensure any insecure path is only reachable when the new explicit opt-in is true
and document/guard that flag.

---

Duplicate comments:
In `@metrics_utility/library/candlepin/client.py`:
- Around line 28-37: The proxy handling may leave the 'https' proxy value
without a scheme, breaking requests' proxy resolution; update the normalization
so any incoming proxy string missing a scheme gets an explicit scheme (default
to "http://"), then build self.proxies using that normalized proxy for the
'https' key and an explicit "http://{host}" for the 'http' key (use the
normalized host computed from the normalized proxy); adjust the code around the
proxy variable, host extraction, and self.proxies assignment to always supply
scheme-qualified proxy URLs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 553698ad-1d2c-4d0f-ade9-2ecfd3d4f5e1

📥 Commits

Reviewing files that changed from the base of the PR and between dc81e78 and 24e4774.

📒 Files selected for processing (4)
  • metrics_utility/library/candlepin/client.py
  • metrics_utility/library/candlepin/lifecycle.py
  • metrics_utility/management/validation.py
  • sonar-project.properties
✅ Files skipped from review due to trivial changes (2)
  • sonar-project.properties
  • metrics_utility/management/validation.py

Comment thread metrics_utility/library/candlepin/client.py Outdated
Comment thread metrics_utility/management/validation.py Outdated
- Updated the `CandlepinClient` to enable TLS server verification by default, requiring explicit opt-in to disable it for controlled environments.
- Refactored the database functions in `validation.py` to use a new `_upsert_conf_settings` method for better code reuse and clarity.
- Improved unit tests to cover new TLS verification behavior and ensure correct handling of certificate and registration data in the database.
@cshiels-ie cshiels-ie changed the title Candle pin v2 [PENDING] Candle pin v2 Apr 1, 2026
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Comment thread metrics_utility/management/validation.py Outdated
- Introduced a new management command `candlepin_manage` for handling Candlepin consumer registration and certificate lifecycle management.
- Enhanced the `_upsert_conf_settings` function in `validation.py` to return success or failure status, improving error handling.
- Updated logging to provide clearer feedback on the success of certificate and registration operations.
- Added unit tests for the new management command to ensure proper functionality and error handling in various scenarios.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
metrics_utility/management/commands/candlepin_manage.py (1)

119-174: Consider extracting credential validation to reduce complexity.

SonarCloud flagged cognitive complexity of 17 (threshold 15). The credential validation block (lines 136-146) could be extracted into a helper function.

Suggested refactor
+    def _validate_credentials(self, username, password, org):
+        """Return list of missing credential error messages, or empty list if all present."""
+        missing = []
+        if not username:
+            missing.append('username (pass --username or set SUBSCRIPTIONS_USERNAME in conf_setting)')
+        if not password:
+            missing.append('password (pass --password or set SUBSCRIPTIONS_PASSWORD in conf_setting)')
+        if not org:
+            missing.append('org (pass --org or ensure LICENSE.account_number is set in conf_setting)')
+        return missing
+
     def _handle_register(self, options):
         # ... existing code ...
         
-        missing = []
-        if not username:
-            missing.append('username (pass --username or set SUBSCRIPTIONS_USERNAME in conf_setting)')
-        if not password:
-            missing.append('password (pass --password or set SUBSCRIPTIONS_PASSWORD in conf_setting)')
-        if not org:
-            missing.append('org (pass --org or ensure LICENSE.account_number is set in conf_setting)')
+        missing = self._validate_credentials(username, password, org)
         if missing:
             for m in missing:
                 self.stderr.write(f'Missing required value: {m}')
             return False
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@metrics_utility/management/commands/candlepin_manage.py` around lines 119 -
174, Extract the credential resolution and validation block inside
_handle_register into a helper function (e.g.,
_resolve_and_validate_credentials) that calls
_fetch_registration_credentials_from_db, merges CLI options
(options['username'], options['password'], options['org']) with DB values, and
returns a tuple (username, password, org) or None/False on failure; move the
missing-check logic (building the missing list and writing to self.stderr for
each missing message) into that helper and have _handle_register call it and
abort if it indicates failure, keeping all existing messages and behavior
unchanged and preserving use of options keys and db_install_uuid handling.
metrics_utility/test/library/test_candlepin_client.py (2)

122-126: Consider using endswith for file mode assertion.

The string slice [-3:] works but is less readable than endswith. Static analysis flagged this.

Suggested fix
     def test_files_have_mode_0600(self, cert_pem=None, key_pem=None):
         cert_pem, key_pem = _generate_cert_and_key()
         with CandlepinClient._temp_cert_files(cert_pem, key_pem) as (cp, kp):
-            assert oct(os.stat(cp).st_mode)[-3:] == '600'
-            assert oct(os.stat(kp).st_mode)[-3:] == '600'
+            assert oct(os.stat(cp).st_mode).endswith('600')
+            assert oct(os.stat(kp).st_mode).endswith('600')
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@metrics_utility/test/library/test_candlepin_client.py` around lines 122 -
126, Replace the string-slice file mode assertions in test_files_have_mode_0600
with clearer endswith checks: inside the context manager using
CandlepinClient._temp_cert_files(cert_pem, key_pem) change both occurrences that
currently use oct(os.stat(...).st_mode)[-3:] == '600' to use
oct(os.stat(...).st_mode).endswith('600') so the intent is more readable and
satisfies static analysis.

122-122: Remove unused default parameters from test method signature.

The method signature includes cert_pem=None, key_pem=None but immediately regenerates them inside. This appears to be a copy-paste artifact.

Suggested fix
-    def test_files_have_mode_0600(self, cert_pem=None, key_pem=None):
+    def test_files_have_mode_0600(self):
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@metrics_utility/test/library/test_candlepin_client.py` at line 122, The test
method test_files_have_mode_0600 includes unused default parameters
cert_pem=None and key_pem=None which are immediately regenerated; remove these
parameters from the method signature so it becomes def
test_files_have_mode_0600(self): and update any local references if necessary
(the body already regenerates cert_pem/key_pem), ensuring no external test
harness expects those parameters.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@metrics_utility/management/commands/candlepin_manage.py`:
- Around line 119-174: Extract the credential resolution and validation block
inside _handle_register into a helper function (e.g.,
_resolve_and_validate_credentials) that calls
_fetch_registration_credentials_from_db, merges CLI options
(options['username'], options['password'], options['org']) with DB values, and
returns a tuple (username, password, org) or None/False on failure; move the
missing-check logic (building the missing list and writing to self.stderr for
each missing message) into that helper and have _handle_register call it and
abort if it indicates failure, keeping all existing messages and behavior
unchanged and preserving use of options keys and db_install_uuid handling.

In `@metrics_utility/test/library/test_candlepin_client.py`:
- Around line 122-126: Replace the string-slice file mode assertions in
test_files_have_mode_0600 with clearer endswith checks: inside the context
manager using CandlepinClient._temp_cert_files(cert_pem, key_pem) change both
occurrences that currently use oct(os.stat(...).st_mode)[-3:] == '600' to use
oct(os.stat(...).st_mode).endswith('600') so the intent is more readable and
satisfies static analysis.
- Line 122: The test method test_files_have_mode_0600 includes unused default
parameters cert_pem=None and key_pem=None which are immediately regenerated;
remove these parameters from the method signature so it becomes def
test_files_have_mode_0600(self): and update any local references if necessary
(the body already regenerates cert_pem/key_pem), ensuring no external test
harness expects those parameters.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 96ae9b67-97c3-4d38-800e-a081f65c6d21

📥 Commits

Reviewing files that changed from the base of the PR and between dc81e78 and def7e32.

📒 Files selected for processing (9)
  • metrics_utility/library/candlepin/client.py
  • metrics_utility/library/candlepin/lifecycle.py
  • metrics_utility/management/commands/candlepin_manage.py
  • metrics_utility/management/validation.py
  • metrics_utility/test/library/test_candlepin_client.py
  • metrics_utility/test/management/__init__.py
  • metrics_utility/test/management/commands/__init__.py
  • metrics_utility/test/management/commands/test_candlepin_manage.py
  • sonar-project.properties
🚧 Files skipped from review as they are similar to previous changes (1)
  • sonar-project.properties

- Moved credential resolution and validation logic to a new method `_resolve_and_validate_credentials`, improving code organization and readability.
- Updated `_handle_register` to utilize the new method for resolving credentials, ensuring that required fields are validated before proceeding with registration.
- Enhanced error handling by providing clearer feedback when required values are missing.
@SherinV SherinV changed the title [PENDING] Candle pin v2 AAP-68113 [PENDING] Candle pin v2 Apr 14, 2026
@sonarqubecloud
Copy link
Copy Markdown

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