Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/bench-v3.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@@
@@
-"cel.dev/cel-go/cel"
+"github.com/google/cel-go/cel"

@@
@@
-"cel.dev/cel-go/common/types/ref"
+"github.com/google/cel-go/common/types/ref"
18 changes: 11 additions & 7 deletions .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Install Go
uses: buildjet/setup-go@555ce355a95ff01018ffcf8fbbd9c44654db8374 # v5.0.2
with:
go-version: 1.26.x
cache: false
- name: Checkout code
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
fetch-depth: 0
- name: Install Go
uses: buildjet/setup-go@555ce355a95ff01018ffcf8fbbd9c44654db8374 # v5.0.2
with:
go-version-file: go.mod
cache: false
- name: Post "benchmark running" comment
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
with:
Expand Down Expand Up @@ -78,12 +78,16 @@ jobs:
# the same benchmark suite — only the implementation under test differs.
cp serialize_bench_test.go .tmp/bench/base/serialize_bench_test.go
cp run_expression_bench_test.go .tmp/bench/base/run_expression_bench_test.go
if rg -q '^module github.com/flanksource/gomplate/v3$' .tmp/bench/base/go.mod
then
go run github.com/uber-go/gopatch@v0.4.0 -p .github/bench-v3.patch .tmp/bench/base/run_expression_bench_test.go
fi
- name: Compile benchmark binaries
run: |
cd .tmp/bench/base
go test -c -o "$GITHUB_WORKSPACE/.tmp/bench/base.test" github.com/flanksource/gomplate/v3
go test -c -o "$GITHUB_WORKSPACE/.tmp/bench/base.test" .
cd "$GITHUB_WORKSPACE"
go test -c -o .tmp/bench/head.test github.com/flanksource/gomplate/v3
go test -c -o .tmp/bench/head.test .
- name: Benchmark interleaved base and head
run: |
: > bench-base.txt
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ name: "CodeQL"

on:
push:
branches: [ main ]
branches: [ main, 3.x ]
tags: [ 'v*' ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ main ]
branches: [ main, 3.x ]
schedule:
- cron: '42 18 * * 0'

Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ on:
push:
branches:
- main
- 3.x
pull_request:

permissions:
Expand All @@ -13,10 +14,10 @@ jobs:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- uses: buildjet/setup-go@555ce355a95ff01018ffcf8fbbd9c44654db8374 # v5.0.2
with:
go-version: 1.22.x
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
go-version-file: go.mod
- name: golangci-lint
uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0
with:
Expand Down
27 changes: 27 additions & 0 deletions .github/workflows/release-policy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Release policy

on:
pull_request:
branches: [main, 3.x]
push:
branches: [main, 3.x]

permissions:
contents: read

jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
- uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
with:
node-version: 24
- name: Install release verification dependencies
run: npm install --prefix .tmp/release-check --package-lock=false --no-audit --no-fund semantic-release@25.0.9 @semantic-release/commit-analyzer@13.0.1 yaml@2.8.1 semver@7.7.2
- name: Verify candidate release and branch range
env:
RELEASE_BRANCH: ${{ github.base_ref || github.ref_name }}
run: node hack/verify-release.mjs "$RELEASE_BRANCH"
12 changes: 9 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ on:
push:
branches:
- main
- 3.x
permissions:
contents: read

Expand All @@ -18,8 +19,12 @@ jobs:
egress-policy: audit

- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
- uses: cycjimmy/semantic-release-action@b12c8f6015dc215fe37bc154d4ad456dd3833c90 # v6.0.0
id: semantic
with:
semantic_version: 25.0.9
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
outputs:
Expand All @@ -29,7 +34,7 @@ jobs:
bump-clients:
runs-on: ubuntu-latest
needs: [semantic-release]
if: needs.semantic-release.outputs.new-release-published == 'true'
if: needs.semantic-release.outputs.new-release-published == 'true' && startsWith(needs.semantic-release.outputs.release-version, '3.')
strategy:
matrix:
repos: ["mission-control", "canary-checker", "commons", "config-db", "duty"]
Expand All @@ -42,7 +47,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
with:
go-version: v1.22.x
go-version-file: go.mod

- name: Create commits
run: |
Expand All @@ -51,7 +56,8 @@ jobs:
go get github.com/flanksource/gomplate/v3@v${{ needs.semantic-release.outputs.release-version }}
go mod tidy
if [ -d "hack/generate-schemas" ]; then
cd hack/generate-schemas && go mod tidy
(cd hack/generate-schemas
go mod tidy)
fi

- name: Create Pull Request
Expand Down
35 changes: 35 additions & 0 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Dependency security
on:
push:
branches: [main, 3.x]
pull_request:
schedule:
- cron: '0 6 * * *'
workflow_dispatch:
permissions:
contents: read
jobs:
scan:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
ref: ${{ (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && fromJSON('["main", "3.x"]') || fromJSON(format('[{0}]', toJSON(github.ref))) }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
ref: ${{ matrix.ref }}
- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
with:
go-version-file: go.mod
- name: Scan Go dependencies
run: go run golang.org/x/vuln/cmd/govulncheck@v1.9.0 ./...
- uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d
with:
package_json_file: web/package.json
- uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b
with:
node-version: 24
- run: pnpm -C web install --frozen-lockfile
- name: Scan production web dependencies
run: pnpm -C web audit --prod --audit-level low
7 changes: 4 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ on:
push:
branches:
- main
- 3.x
pull_request:

permissions:
Expand All @@ -12,11 +13,11 @@ jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
- name: Install Go
uses: buildjet/setup-go@555ce355a95ff01018ffcf8fbbd9c44654db8374 # v5.0.2
with:
go-version: 1.22.x
- name: Checkout code
uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
go-version-file: go.mod
- name: Test
run: go test ./...
11 changes: 6 additions & 5 deletions .github/workflows/web.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ on:
push:
branches:
- main
- 3.x
pull_request:

permissions:
Expand All @@ -17,12 +18,12 @@ jobs:
name: generated definitions are current
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
- name: Install Go
uses: buildjet/setup-go@555ce355a95ff01018ffcf8fbbd9c44654db8374 # v5.0.2
with:
go-version: 1.22.x
- name: Checkout code
uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
go-version-file: go.mod
- name: Check for drift
run: make monarch-check

Expand All @@ -35,11 +36,11 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d # v3.0.0
with:
version: 10
package_json_file: web/package.json
- name: Install Node
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
with:
node-version: 22
node-version: 24
cache: pnpm
cache-dependency-path: web/pnpm-lock.yaml
- name: Install dependencies
Expand Down
12 changes: 10 additions & 2 deletions .releaserc
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
branches:
- name: 3.x
range: 3.x
channel: 3.x
- name: main
plugins:
- - "@semantic-release/commit-analyzer"
- releaseRules:
- { breaking: true, release: major }
- { type: doc, scope: README, release: patch }
- { type: fix, release: patch }
- { type: chore, release: patch }
Expand All @@ -13,8 +17,12 @@ plugins:
parserOpts:
noteKeywords:
- MAJOR RELEASE
- "@semantic-release/release-notes-generator"
- BREAKING CHANGE
- BREAKING CHANGES
- - "@semantic-release/release-notes-generator"
- parserOpts:
noteKeywords: ["MAJOR RELEASE", "BREAKING CHANGE", "BREAKING CHANGES"]
- - "@semantic-release/github"
# From: https://github.com/semantic-release/github/pull/487#issuecomment-1486298997
- successComment: false
failTitle: false
failTitle: false
33 changes: 33 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Supported versions and security maintenance

| Branch | Go module | CEL module | Support |
| --- | --- | --- | --- |
| main (before v4 publication) | github.com/flanksource/gomplate/v3 | github.com/google/cel-go | Active v3 publication |
| main (after v4 publication) | github.com/flanksource/gomplate/v4 | cel.dev/cel-go | Active development |
| 3.x | github.com/flanksource/gomplate/v3 | github.com/google/cel-go | Security fixes only |

The v3 maintenance line starts at v3.24.90. There is no announced end-of-support date. Security patches preserve the v3 API, expression behavior, and CEL import path. Each patch must identify its advisory and use the lowest compatible fixed dependency version. Ordinary feature and dependency refreshes belong on main. Security fixes should be applied to every affected supported branch.

Renovate processes both branches. Routine updates are disabled on 3.x, while vulnerability fixes require review. OSV checks direct dependencies; daily Go vulnerability and production web dependency scans supplement them, including transitive dependencies. A scheduled scan runs from main and explicitly checks out both supported branches. Failed scans require investigation; scanner errors are not passing results.

Until main publishes v4.0.0, publish v3 security fixes from main and keep the 3.x branch synchronized with that published history. Semantic-release does not allow a maintenance branch to publish a version newer than the active main release line. After main publishes v4, v3.x patch releases are published from 3.x. Existing downstream v3 dependency-update PR automation runs only for v3 releases. Consumers must migrate explicitly to v4.

## Migrating to v4

The initial security maintenance patch updates Go to 1.26.10 (including GO-2026-6809), x/net to 0.62.0 (GO-2026-6860 and GO-2026-6866), OpenTelemetry to 1.42.0 (GO-2026-5158), and their required dependency graph. This includes fixed x/text and x/mod versions. The web lockfile resolves DOMPurify 3.4.17, addressing the five advisories reported for 3.4.13. CEL remains at 0.31.0 on 3.x.

Change Go imports from github.com/flanksource/gomplate/v3 to github.com/flanksource/gomplate/v4. When supplying CEL environment options or using AST, evaluation, or value types, change CEL imports from github.com/google/cel-go to cel.dev/cel-go. Do not mix the old and new CEL types.

The initial v4 migration must use a Conventional Commit with a BREAKING CHANGE footer (or the existing MAJOR RELEASE footer) so semantic-release selects v4.0.0. The release analyzer and notes generator recognize both. Local preparation does not publish a release; publishing happens only after the reviewed migration is merged to main.

## Verify release configuration without publishing

Run from the repository root:

```sh
npm install --prefix .tmp/release-check --package-lock=false --no-audit --no-fund semantic-release@25.0.9 @semantic-release/commit-analyzer@13.0.1 yaml@2.8.1 semver@7.7.2
node hack/verify-release.mjs main
go test ./internal/releasepolicy
```

This checks the actual unreleased commits against the target branch's normalized semantic-release range and verifies that the candidate version matches the Go module major. Pass 3.x instead of main when validating a maintenance release. It also checks synthetic breaking and security-fix commits, workflow syntax, and the v3 downstream-update guard. The Release policy workflow runs this check before PRs are merged. It does not create commits, tags, releases, or external PRs.
62 changes: 62 additions & 0 deletions cache_keys_spec_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package gomplate

import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

var _ = Describe("cache key boundaries", func() {
It("keeps delimiter and body boundaries distinct on cache hits", func() {
for _, label := range []string{"", "explicit-delimiter-key"} {
for _, template := range []Template{
{LeftDelim: "$(", RightDelim: ")", Template: "Hi", CacheKey: label},
{LeftDelim: "$", RightDelim: ")", Template: "(Hi", CacheKey: label},
} {
for range 2 {
value, err := RunTemplate(nil, template)
Expect(err).NotTo(HaveOccurred())
Expect(value).To(Equal(template.Template))
}
}
}
})

It("keeps explicit Go template cache labels separate", func() {
first := Template{Template: "hello", CacheKey: "first"}
second := first
second.CacheKey = "second"
Expect(first.autoCacheKey(nil)).NotTo(Equal(second.autoCacheKey(nil)))
})

It("keeps environment variable boundaries distinct", func() {
template := Template{Expression: "1"}
Expect(template.autoCacheKey(map[string]any{"a-b": 1})).
NotTo(Equal(template.autoCacheKey(map[string]any{"a": 1, "b": 1})))
})

It("keeps strict semantics separate from explicit key prefixes", func() {
for _, strictFirst := range []bool{false, true} {
celExpressionCache.Flush()
for _, strict := range []bool{strictFirst, !strictFirst, strictFirst} {
key := "strict:boundary"
if strict {
key = "boundary"
}
value, err := RunExpression(map[string]any{"row": map[string]any{}}, Template{
Expression: "row.missing == 0", Strict: strict, CacheKey: key,
})
if strict {
Expect(err).To(HaveOccurred())
} else {
Expect(err).NotTo(HaveOccurred())
Expect(value).To(BeTrue())
}
}
}
})

It("keeps native generations separate from explicit key prefixes", func() {
Expect((Template{CacheKey: "1:boundary"}).celCacheKey(nil, 0)).
NotTo(Equal((Template{CacheKey: "boundary"}).celCacheKey(nil, 1)))
})
})
Loading