Skip to content

fix(sslcertificatechain): POST to trigger auto-linking when chain is incomplete - #621

Open
rybrose wants to merge 1 commit into
netscaler:mainfrom
rybrose:fix/sslcertificatechain-incomplete-chain
Open

fix(sslcertificatechain): POST to trigger auto-linking when chain is incomplete#621
rybrose wants to merge 1 commit into
netscaler:mainfrom
rybrose:fix/sslcertificatechain-incomplete-chain

Conversation

@rybrose

@rybrose rybrose commented Jul 1, 2026

Copy link
Copy Markdown

Summary

The sslcertificatechain module never issues the POST that triggers auto-linking. It does a GET, sees the resource exists (NITRO always returns chain status for any existing certkey), compares only the certkeyname field, and returns "no change required".

Root Cause

The create_or_update() flow in module_executor.py:

  1. GETs /nitro/v1/config/sslcertificatechain/<certkeyname> - always returns 200 with chain status
  2. Calls is_resource_identical() - only compares certkeyname (the sole readwrite argument)
  3. Finds it identical and skips - the POST that triggers linking is never issued

Fix

When chaincomplete == "0" in the GET response, force a POST to /nitro/v1/config/sslcertificatechain to trigger auto-linking. This links certificates by content (AKI/SKI matching) regardless of certkey naming.

Includes:

  • Diff output showing chainlinked, chainpossiblelinks, and chaincomplete transitions
  • Idempotent: returns ok when chain is already complete (chaincomplete=1)
  • check_mode support via existing client.send() transport layer (skips non-GET in check mode)
  • Integration test covering --check, link, and idempotent scenarios

Testing

Tested against NetScaler NS14.1 Build 66.54.nc with:

  • 5-level chain (Root > Int1 > Int2 > Int3 > Leaf): links full chain in one POST
  • Multiple leaves from same intermediate: idempotent after first link
  • New leaf from different intermediate: correctly links new path
  • Certs with mismatched certkey name vs CN: links by content not name
  • --check --diff: reports changed with diff, no actual POST made

Example output

TASK [Link certificate chain] ************************************
--- before
+++ after
@@ -1,11 +1,11 @@
 {
     "certkeyname": "my-leaf-cert",
-    "chaincomplete": "0",
-    "chainlinked": ["IssuingCA"],
-    "chainpossiblelinks": ["IntermediateCA", "RootCA"]
+    "chaincomplete": "1",
+    "chainlinked": ["IssuingCA", "IntermediateCA", "RootCA"],
+    "chainpossiblelinks": []
 }

changed: [localhost]

@rybrose
rybrose requested a review from sumanth-lingappa as a code owner July 1, 2026 06:28
@CLAassistant

CLAassistant commented Jul 1, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@rybrose rybrose closed this Jul 1, 2026
@rybrose rybrose reopened this Jul 2, 2026
@rybrose

rybrose commented Jul 2, 2026

Copy link
Copy Markdown
Author

Reopening this PR. To clarify the approach taken here: this fix follows the same established pattern used for other resource-specific quirks in module_executor.py:

  • sslhsmkey (line 510): Swallows error code 1065 on create because NetScaler returns an error on successful HSM key addition
  • systemfile (line 635): Delete-then-add instead of update because the resource cannot be updated in place
  • location (line 648): Special composite primary key handling for updates

All of these use inline if self.resource_name == "..." checks within create_or_update() to handle cases where the generic executor logic does not account for NITRO API behaviour specific to that resource.

The sslcertificatechain resource has the same class of problem: the GET endpoint returns chain status (read-only info), but the POST endpoint triggers an action (auto-linking). The generic executor sees the GET return 200, considers the resource "identical" (since the only readwrite arg is certkeyname which matches), and skips the POST. The chain remains incomplete.

This fix checks chaincomplete == "0" in the GET response and forces the POST when the chain is not yet fully linked. It includes diff output support showing before/after chain state, and is idempotent (returns ok on subsequent runs when chain is already complete).

@rybrose
rybrose force-pushed the fix/sslcertificatechain-incomplete-chain branch from 48be62b to 15d012e Compare July 7, 2026 05:48
…incomplete

The sslcertificatechain module previously did a GET, found the resource
exists (since NITRO always returns chain status for any existing certkey),
and returned 'no change required' without issuing the POST that triggers
auto-linking.

This fix checks the chaincomplete field from the GET response. When the
chain is incomplete (chaincomplete=0), the module now POSTs to trigger
NITRO's auto-linking, which links certificates by content (AKI/SKI
matching) regardless of certkey naming.

Includes:
- Proper diff output showing chainlinked/chainpossiblelinks transitions
- Idempotent: returns ok when chain is already complete (chaincomplete=1)
- check_mode support via existing client.send() transport layer
- Integration test covering check, link, and idempotent scenarios
@rybrose
rybrose force-pushed the fix/sslcertificatechain-incomplete-chain branch from 15d012e to 122e2d5 Compare July 7, 2026 05:56
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.

2 participants