Fix SSL certificate handling in PortainerClientConfig for production profile #156
Labels
No Label
architect:complete
blocked-by:#139
blocks:#140
bug
CI/CD
complexity:low
complexity:medium
complexity:medium
config
depends-on:#124
docker
docs
effort:l
effort:s
effort:xs
epic/development
lead:complete
needs-decision
performance
priority:critical
priority:high
priority:low
priority:medium
security
spike
story-points:1
story-points:3
story-points:5
story-points:8
tech-debt
test
user-story
architect:complete
complexity:high
complexity:low
complexity:medium
cross-repo
cross-repo-dev
dev:in-progress
effort:l
effort:m
effort:s
effort:xl
effort:xs
epic
analytics
epic
development
epic
devops
epic
infra
epic
observability
epic
platform
epic
product
lead:complete
needs-decision
pipeline-complete
pipeline-error
pipeline-running
priority
later
priority
next
priority
now
start-pipeline
status
acceptance
status
blocked
status
done
status
in progress
status
in review
status
in testing
status
ready
status
refine
status
triage
subtask
type
analysis
type
bug
type
hygiene
type
mantainence
type
story
user-story
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: Hithomelabs/CFTunnels#156
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Description
When the portainer-automation service runs with the
prodprofile and connects to the production Portainer athttps://192.168.0.100:9443(self-signed SSL certificate), I want the HTTPS client to trust that certificate, so the SSL handshake succeeds and the service can authenticate and deploy stacks to production.Root cause:
PortainerClientConfig.javahas a@Profile("!local")bean that applies strict SSL validation. Sinceprodis notlocal, it matches this profile and uses a defaultRestTemplatewhich rejects the self-signed cert. Thelocalprofile has a trust-all SSL bean, butprodhas no equivalent.Error observed:
(bad_certificate) Failed to parse server certificatesAcceptance Criteria
Happy path — Prod profile uses trust-all SSL:
GIVEN the
prodSpring profile is activeWHEN the
portainerRestTemplatebean is createdTHEN it uses a trust-all SSL configuration (same as
local) and successfully connects tohttps://192.168.0.100:9443Edge case — Non-local, non-prod profiles still validate SSL:
GIVEN a profile like
ciortestis activeWHEN the
portainerRestTemplatebean is createdTHEN it uses strict SSL validation (standard
RestTemplate)Code quality — DRY trust-all logic:
GIVEN the
localandprodprofiles both need trust-all SSLWHEN the code is reviewed
THEN the trust-all SSL
RestTemplatecreation logic is extracted into a shared private/helper method to avoid duplicationTechnical Notes
Changes required in
PortainerClientConfig.java:Add a
@Profile("prod")bean that creates a trust-all SSLRestTemplate(same logic as thelocalbean) — annotated with@Bean(name = "portainerRestTemplate")Update the
@Profile("!local")bean annotation to@Profile("!local & !prod")(Spring expression language) so it no longer catches theprodprofileExtract the trust-all SSL
RestTemplatecreation into a shared private method (e.g.,createTrustAllRestTemplate()) used by both thelocalandprodbeansFile to modify:
portainer-automation/src/main/java/com/hithomelabs/portainer/config/PortainerClientConfig.javaTesting:
local,prod,ci,test)SPRING_PROFILES_ACTIVE=prodand confirm SSL handshake succeedsDependencies
prodprofile is fully wired)Story Points: 3
Priority: high
🏛️ Architectural Review: Developer's Solution (PR #157) vs. Proposed Alternatives
Requested by: @hitanshu — verify the developer's fix against the architect's alternatives.
✅ Verdict Summary
The developer's fix is CORRECT for the immediate blocker, but it implements Option A (the quick profile-based fix) rather than my recommended Option B (property-driven SSL). One latent bug I flagged remains in the merged code.
prodprofile now gets trust-all SSLbuildTrustAllRestTemplate()extraction is clean📋 What the Developer Did (PR #157, merged)
This is exactly Option A from my architecture review on #124 (comment #2469): a profile-based fix that adds
@Profile("prod")and negates it out of the strict bean.⚠️ The Latent Bug — Still in Main
In my review (comment #2469 on #124) I flagged that negation-based profiling breaks the default profile:
This is unchanged in the merged code:
localdevdocker.hithomelabs.com(self-signed)prod192.168.0.100:9443(self-signed)192.168.0.100:9442(self-signed)bad_certificateciportainer-test:9000(HTTP)Risk level: Low today (all real deployments use explicit profiles), but a footgun — anyone running the jar without
SPRING_PROFILES_ACTIVE(e.g., local dev, debugging, or a future forgotten deployment) hits the exact error this issue was meant to fix.🧩 Why the Developer Chose Option A
Timeline (2026-07-09):
20:54— #156 created with technical notes prescribing the profile-based fix20:55:38— My architecture review posted on #124 recommending Option B (property-driven)20:57:16— PR #157 opened implementing Option A (per #156's notes)20:58:59— MergedConclusion: The developer followed the issue's technical notes faithfully. The timing (PR opened ~2 min after my review) means the recommendation likely wasn't seen before merge. This is a process gap, not a developer error.
📌 Recommendation (Low-Effort Follow-up)
portainer.trust-all-ssl=truein defaultapplication.properties(dev base URL is self-signed), orSPRING_PROFILES_ACTIVE=prodexplicitly to the prod docker-compose service (belt-and-suspenders)🏗️ For Future SSL Work
When the next profile needs SSL handling, migrate to the property-driven approach (
portainer.trust-all-sslflag) I recommended in comment #2469 on #124 — it eliminates the whole class of@Profilenegation bugs.Architect verdict posted by Archie (Architect Agent)
Date: 2026-08-02