Skip to content

Commit 9d03316

Browse files
indrorairbyspbsolubleclaudeCopilot
authored
Merge 2.5.2 to main (#67)
* feat: release 2.5.0 2.5.0: CA Bundle with ConfigMap + GKE Ambient Credentials Documentation * release: 2.5.1 * feat: release 2.5.0 (#62) 2.5.0: CA Bundle with ConfigMap + GKE Ambient Credentials Documentation Co-authored-by: Matthew H. Irby <irby@users.noreply.github.com> * feat: add client caching to reduce OAuth token requests Previously, every certificate request reconciliation created a new Command API client, which meant a new OAuth token was fetched for each request. For customers with OAuth provider quotas, this caused rate limiting issues. This change introduces a ClientCache that: - Caches Command API clients by configuration hash - Reuses cached clients across reconciliations for the same issuer - Allows the underlying oauth2 library's token caching to work as intended - Is thread-safe for concurrent reconciliations The cache key is a SHA-256 hash of all configuration fields that affect the client connection (hostname, API path, credentials, scopes, etc.), ensuring different issuers get different clients while the same issuer reuses its client. Fixes: OAuth token re-authentication on every request Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore(scripts): update scripting usability * feat: update keyfactor-auth-client-go to v1.3.1 Signed-off-by: Matthew H. Irby <matt.irby@keyfactor.com> * chore: remove test short circuit Signed-off-by: Matthew H. Irby <matt.irby@keyfactor.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Revert "Potential fix for pull request finding" This reverts commit 19bc19b. * chore: cleanup Signed-off-by: Matthew H. Irby <matt.irby@keyfactor.com> * chore: break build & test into its own workflow Signed-off-by: Matthew H. Irby <matt.irby@keyfactor.com> * fix: remove lint from CI Signed-off-by: Matthew H. Irby <matt.irby@keyfactor.com> * chore(docs): update CHANGELOG Signed-off-by: Matthew H. Irby <matt.irby@keyfactor.com> --------- Signed-off-by: Matthew H. Irby <matt.irby@keyfactor.com> Co-authored-by: Morgan Gangwere <470584+indrora@users.noreply.github.com> Co-authored-by: Matthew H. Irby <irby@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Matthew H. Irby <matt.irby@keyfactor.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Add missing namespace specification + address linting issues (#66) * fix: log errors from Enrollment API call Signed-off-by: Matthew H. Irby <matt.irby@keyfactor.com> * fix: add missing namespaces, add linting to catch issues Signed-off-by: Matthew H. Irby <matt.irby@keyfactor.com> * feat: add linting Signed-off-by: Matthew H. Irby <matt.irby@keyfactor.com> * chore: address lint issues Signed-off-by: Matthew H. Irby <matt.irby@keyfactor.com> * chore: update CHANGELOG Signed-off-by: Matthew H. Irby <matt.irby@keyfactor.com> * chore: apply copilot feedback Signed-off-by: Matthew H. Irby <matt.irby@keyfactor.com> * feat: fix typo Signed-off-by: Matthew H. Irby <matt.irby@keyfactor.com> * feat: copilot suggestions Signed-off-by: Matthew H. Irby <matt.irby@keyfactor.com> --------- Signed-off-by: Matthew H. Irby <matt.irby@keyfactor.com> --------- Signed-off-by: Matthew H. Irby <matt.irby@keyfactor.com> Co-authored-by: Matthew H. Irby <irby@users.noreply.github.com> Co-authored-by: spb <1661003+spbsoluble@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Matthew H. Irby <matt.irby@keyfactor.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
1 parent 3dcb8de commit 9d03316

27 files changed

Lines changed: 1311 additions & 421 deletions

.github/workflows/test.yml

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1-
name: Build and Test
1+
name: Build Test and Lint
22
on:
3+
workflow_dispatch:
34
pull_request:
45
push:
56
branches:
67
- 'main'
78
- 'release-*.*'
89
jobs:
910
build:
10-
name: Build and Lint
11+
name: Build and Test
1112
runs-on: ubuntu-latest
12-
timeout-minutes: 8
13+
timeout-minutes: 10
1314
steps:
1415
# Checkout code
1516
# https://github.com/actions/checkout
@@ -30,19 +31,13 @@ jobs:
3031
# Build Go binary
3132
- run: go build -v cmd/main.go
3233

33-
- name: Regenerate CRDs
34-
run: make generate manifests
35-
36-
- name: Check for CRD drift
37-
run: |
38-
git diff --compact-summary --exit-code || \
39-
(echo; echo "Unexpected difference in directories after code generation. Run 'make generate manifests' and commit."; exit 1)
34+
- run: go test ./...
4035

41-
test:
42-
name: Go Test
36+
lint:
37+
name: Lint
4338
needs: build
4439
runs-on: ubuntu-latest
45-
timeout-minutes: 15
40+
timeout-minutes: 10
4641
steps:
4742
# Checkout code
4843
# https://github.com/actions/checkout
@@ -57,6 +52,23 @@ jobs:
5752
go-version-file: 'go.mod'
5853
cache: true
5954

60-
# Run Go tests
61-
- name: Run go test
62-
run: go test -v ./...
55+
- name: Install Helm
56+
uses: azure/setup-helm@v3.5
57+
58+
# Run Go linters
59+
# https://github.com/golangci/golangci-lint-action
60+
- name: Run linters
61+
uses: golangci/golangci-lint-action@v7
62+
with:
63+
version: v2.4.0
64+
65+
- name: Regenerate CRDs
66+
run: make generate manifests
67+
68+
- name: Check for CRD drift
69+
run: |
70+
git diff --compact-summary --exit-code -- config/crd deploy/charts || \
71+
(echo; echo "Unexpected difference in directories after code generation. Run 'make generate manifests' and commit."; exit 1)
72+
73+
- name: Lint Helm manifests
74+
run: make lint-manifests

.golangci.yml

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,46 @@
1-
run:
2-
# timeout for analysis, e.g. 30s, 5m, default is 1m
3-
timeout: 12m
4-
5-
skip-dirs:
6-
- testdata$
7-
- test/mock
8-
- go/pkg/mod
9-
10-
skip-files:
11-
- ".*\\.pb\\.go"
12-
1+
version: "2"
132
linters:
143
enable:
154
- bodyclose
165
- durationcheck
176
- errorlint
18-
- goimports
19-
- revive
7+
- gocritic
208
- gosec
219
- misspell
2210
- nakedret
11+
- nolintlint
12+
- revive
2313
- unconvert
2414
- unparam
25-
- whitespace
26-
- gocritic
27-
- nolintlint
28-
29-
linters-settings:
30-
revive:
31-
# minimal confidence for issues, default is 0.8
32-
confidence: 0.0
15+
settings:
16+
revive:
17+
confidence: 0
18+
rules:
19+
- name: var-naming
20+
disabled: true
21+
exclusions:
22+
generated: lax
23+
presets:
24+
- comments
25+
- common-false-positives
26+
- legacy
27+
- std-error-handling
28+
paths:
29+
- .*\.pb\.go
30+
- testdata$
31+
- test/mock
32+
- third_party$
33+
- builtin$
34+
- examples$
35+
formatters:
36+
enable:
37+
- goimports
38+
exclusions:
39+
generated: lax
40+
paths:
41+
- .*\.pb\.go
42+
- testdata$
43+
- test/mock
44+
- third_party$
45+
- builtin$
46+
- examples$

.kube-linter.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
checks:
2+
addAllBuiltIn: true
3+
# Add project-specific exclusions below as needed, e.g.:
4+
# exclude:
5+
# - "unset-cpu-requirements"
6+
# - "unset-memory-requirements"

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
# v2.5.2
2+
## Fixes
3+
- Fixes an issue where a namespace may not be properly applied if applying the Helm template without a namespace specified / using `kubectl apply -f` directly with the rendered template.
4+
- Fixes an issue where the error message from a failed Enrollment API call is not logged.
5+
## Chores
6+
- Update GitHub Actions workflow to check for policy enforcement on Helm chart rendered manifests in addition to checking for drift in generated CRDs.
7+
- Fixes various linting issues in the codebase.
8+
19
# v2.5.1
210
## Fixes
311
- Fixes an issue where OAuth 2.0 client credentials were being regenerated on every API call.

CONTRIBUTING.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Command Cert Manager Issuer Contribution Guide
2+
3+
## Requirements
4+
- Go (>= 1.24)
5+
- golangci-lint (>= 2.4.0) ([installation notes](https://github.com/golangci/golangci-lint?tab=readme-ov-file#install-golangci-lint))
6+
- helm (>= 3.x) — required to render chart templates for manifest linting ([installation notes](https://helm.sh/docs/intro/install/))
7+
- conftest — policy testing tool powered by Open Policy Agent; installed automatically by `make lint-manifests`
8+
9+
## Installing dependencies
10+
Project dependencies can be installed by running the following:
11+
12+
```bash
13+
go mod download
14+
```
15+
16+
The following command can be used to add missing requirements or remove unused modules:
17+
18+
```bash
19+
go mod tidy
20+
```
21+
22+
## Running unit tests
23+
The following command can be run to run the project unit tests:
24+
25+
```bash
26+
go test -v ./...
27+
```
28+
29+
## Running linters
30+
The project uses golangci-lint to lint the codebase. The following command can be run to run the linters:
31+
32+
```bash
33+
golangci-lint run
34+
```
35+
36+
or, alternatively:
37+
38+
```bash
39+
make lint
40+
```
41+
42+
## Updating generated manifests
43+
44+
This command will update the generated custom resource definitions under `config/crd/bases`:
45+
46+
```bash
47+
make generate manifests
48+
```
49+
50+
> [!IMPORTANT]
51+
> There is no automated process to automatically update the CRDs under `deploy/charts/command-cert-manager-issuer`. If any changes are made to the CRDs, the generated CRDs under `config/crd/bases` must be copied to `deploy/charts/command-cert-manager-issuer/crds` to ensure the Helm chart is up to date.
52+
53+
## Linting Helm manifests
54+
55+
The Helm chart under `deploy/charts/command-cert-manager-issuer` is linted with two tools on every PR:
56+
- **conftest** — runs custom Rego policies located in the [`policy/`](policy/) directory against the rendered manifests
57+
58+
To run both checks locally:
59+
60+
```bash
61+
make lint-manifests
62+
```
63+
64+
`conftest` is downloaded automatically into `bin/` on first use; no manual installation is required.
65+
66+
To inspect the rendered templates without linting:
67+
68+
```bash
69+
make helm-template
70+
```
71+
72+
### Adding or modifying policies
73+
74+
Rego policies live in [`policy/`](policy/). Each `.rego` file in that directory is evaluated by conftest against every resource in the rendered chart. Add a new `.rego` file to enforce additional rules. For example, `policy/roles.rego` enforces that all `Role` resources declare an explicit namespace.
75+
76+
kube-linter checks can be tuned in [.kube-linter.yaml](.kube-linter.yaml). To exclude a check, add its name under the `exclude` key.
77+
78+
## Running end-to-end tests
79+
A comprehensive end-to-end test suite is available to verify the issuer code works against cert-manager and a Keyfactor Command instance.
80+
81+
Instructions on how to run the end-to-end test suite can be found [here](./e2e/README.md).

Makefile

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ endif
1717
# tools. (i.e. podman)
1818
CONTAINER_TOOL ?= docker
1919

20+
# Helm chart and Conftest policy directory for manifest linting
21+
HELM_CHART_DIR ?= deploy/charts/command-cert-manager-issuer
22+
HELM_RELEASE_NAME ?= command-cert-manager-issuer
23+
POLICY_DIR ?= policy
24+
2025
# Setting SHELL to bash allows bash commands to be executed by recipes.
2126
# Options are set to exit when a recipe line exits non-zero or a piped command fails.
2227
SHELL = /usr/bin/env bash -o pipefail
@@ -78,6 +83,20 @@ lint: golangci-lint ## Run golangci-lint linter & yamllint
7883
lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes
7984
$(GOLANGCI_LINT) run --fix
8085

86+
.PHONY: helm-template
87+
helm-template: ## Render Helm chart templates to stdout (includes CRDs).
88+
helm template $(HELM_RELEASE_NAME) $(HELM_CHART_DIR) --include-crds
89+
90+
.PHONY: lint-manifests
91+
lint-manifests: conftest ## Run Conftest policy checks against every CI values file in $(HELM_CHART_DIR)/ci/.
92+
@failed=0; \
93+
for f in $(HELM_CHART_DIR)/ci/*-values.yaml; do \
94+
echo "==> $$(basename $$f)"; \
95+
helm template $(HELM_RELEASE_NAME) $(HELM_CHART_DIR) --include-crds -f "$$f" \
96+
| $(CONFTEST) test --policy $(POLICY_DIR) - || failed=1; \
97+
done; \
98+
exit $$failed
99+
81100
##@ Build
82101

83102
.PHONY: build
@@ -162,18 +181,32 @@ KUSTOMIZE ?= $(LOCALBIN)/kustomize-$(KUSTOMIZE_VERSION)
162181
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen-$(CONTROLLER_TOOLS_VERSION)
163182
ENVTEST ?= $(LOCALBIN)/setup-envtest-$(ENVTEST_VERSION)
164183
GOLANGCI_LINT = $(LOCALBIN)/golangci-lint-$(GOLANGCI_LINT_VERSION)
184+
KUBE_LINTER = $(LOCALBIN)/kube-linter-$(KUBE_LINTER_VERSION)
185+
CONFTEST = $(LOCALBIN)/conftest-$(CONFTEST_VERSION)
165186

166187
## Tool Versions
167188
KUSTOMIZE_VERSION ?= v5.3.0
168189
CONTROLLER_TOOLS_VERSION ?= v0.14.0
169190
ENVTEST_VERSION ?= latest
170-
GOLANGCI_LINT_VERSION ?= v1.60.1
191+
GOLANGCI_LINT_VERSION ?= v2.4.0
192+
KUBE_LINTER_VERSION ?= v0.6.8
193+
CONFTEST_VERSION ?= v0.60.0
171194

172195
.PHONY: kustomize
173196
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary.
174197
$(KUSTOMIZE): $(LOCALBIN)
175198
$(call go-install-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v5,$(KUSTOMIZE_VERSION))
176199

200+
.PHONY: kube-linter
201+
kube-linter: $(KUBE_LINTER) ## Download kube-linter locally if necessary.
202+
$(KUBE_LINTER): $(LOCALBIN)
203+
$(call go-install-tool,$(KUBE_LINTER),golang.stackrox.io/kube-linter/cmd/kube-linter,$(KUBE_LINTER_VERSION))
204+
205+
.PHONY: conftest
206+
conftest: $(CONFTEST) ## Download conftest locally if necessary.
207+
$(CONFTEST): $(LOCALBIN)
208+
$(call go-install-tool,$(CONFTEST),github.com/open-policy-agent/conftest,$(CONFTEST_VERSION))
209+
177210
.PHONY: controller-gen
178211
controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary.
179212
$(CONTROLLER_GEN): $(LOCALBIN)
@@ -187,7 +220,12 @@ $(ENVTEST): $(LOCALBIN)
187220
.PHONY: golangci-lint
188221
golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
189222
$(GOLANGCI_LINT): $(LOCALBIN)
190-
$(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/cmd/golangci-lint,${GOLANGCI_LINT_VERSION})
223+
@[ -f $(GOLANGCI_LINT) ] || { \
224+
set -e; \
225+
echo "Downloading golangci-lint $(GOLANGCI_LINT_VERSION)" ;\
226+
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/$(GOLANGCI_LINT_VERSION)/install.sh | sh -s -- -b $(LOCALBIN) $(GOLANGCI_LINT_VERSION) ;\
227+
mv $(LOCALBIN)/golangci-lint $(GOLANGCI_LINT) ;\
228+
}
191229

192230
# go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist
193231
# $1 - target path with name of binary (ideally with version)

api/v1alpha1/issuer_types.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -201,10 +201,9 @@ func (is *IssuerStatus) HasCondition(conditionType IssuerConditionType, state Co
201201
}
202202

203203
func (is *IssuerStatus) UnsetCondition(conditionType IssuerConditionType) {
204-
conditions := is.Conditions
205-
for i, c := range conditions {
204+
for i, c := range is.Conditions {
206205
if c.Type == conditionType {
207-
is.Conditions = append(conditions[:i], conditions[i+1:]...)
206+
is.Conditions = append(is.Conditions[:i], is.Conditions[i+1:]...)
208207
return
209208
}
210209
}

api/v1alpha1/issuer_types_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func TestIssuerStatus_SetCondition_UpdateConditionStatus(t *testing.T) {
6868
assert.Equal(t, "NewMessage", cond.Message)
6969

7070
// LastTransitionTime should be updated because status changed from ConditionFalse -> ConditionTrue
71-
assert.True(t, cond.LastTransitionTime.Time.After(now.Time), "LastTransitionTime should be more recent if the status changed.")
71+
assert.True(t, cond.LastTransitionTime.After(now.Time), "LastTransitionTime should be more recent if the status changed.")
7272
}
7373

7474
func TestIssuerStatus_SetCondition_NoStatusChange(t *testing.T) {

cmd/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ func main() {
197197
}
198198

199199
if defaultHealthCheckInterval < time.Duration(30)*time.Second {
200-
setupLog.Error(errors.New(fmt.Sprintf("interval %s is invalid, must be greater than or equal to '30s'", healthCheckInterval)), "invalid health check interval")
200+
setupLog.Error(fmt.Errorf("interval %s is invalid, must be greater than or equal to '30s'", healthCheckInterval), "invalid health check interval")
201201
os.Exit(1)
202202
}
203203

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Cluster-wide access configuration — exercises ClusterRole/ClusterRoleBinding
2+
# paths for secret and configmap access, and enables secure metrics.
3+
secretConfig:
4+
useClusterRoleForSecretAccess: true
5+
useClusterRoleForConfigMapAccess: true
6+
metrics:
7+
secure: true

0 commit comments

Comments
 (0)