Skip to content

Commit 6914d0e

Browse files
authored
Merge pull request #3 from Gentleelephant/cherry-pick/merge-upstream-v2-final
feat(costmodel): add prefixed APIs, autocomplete, currency, and cost export improvements
2 parents 8c73754 + d0dfecf commit 6914d0e

606 files changed

Lines changed: 98527 additions & 18617 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,12 @@
1-
## What does this PR change?
2-
*
1+
## Description
2+
<!-- Provide a clear and concise description of what this PR changes. -->
33

4-
## Does this PR relate to any other PRs?
5-
*
4+
## Related Issues
5+
<!-- Link related issues using keywords: Fixes #123, Closes #456, Relates to #789 -->
66

7-
## How will this PR impact users?
8-
*
7+
## User Impact
8+
<!-- Describe any user-facing changes. Is this a breaking change? Is there backwards compatibility? -->
99

10-
## Does this PR address any GitHub or Zendesk issues?
11-
* Closes ...
12-
13-
## How was this PR tested?
14-
*
15-
16-
## Does this PR require changes to documentation?
17-
*
18-
19-
## Have you labeled this PR and its corresponding Issue as "next release" if it should be part of the next OpenCost release? If not, why not?
20-
*
10+
## Testing
11+
<!-- Describe how you tested your changes: unit tests, manual tests, integration tests, etc. -->
12+
<!-- Integration tests: https://github.com/opencost/opencost-integration-tests -->

.github/actions/build-container/action.yaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,5 +52,8 @@ runs:
5252
5353
- name: Build and push (multiarch) OpenCost
5454
shell: bash
55+
env:
56+
IMAGE_TAG: ${{ inputs.image_tag }}
57+
RELEASE_VERSION: ${{ inputs.release_version }}
5558
run: |
56-
just build '${{ inputs.image_tag }}' '${{ inputs.release_version }}'
59+
just build '$IMAGE_TAG' '$RELEASE_VERSION'
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
name: 'Sign Container Image'
2+
description: >-
3+
Sign a container image and attest SLSA v1 build provenance using cosign
4+
keyless (Sigstore) with GitHub Actions OIDC. Callers must check out the
5+
source tree (e.g. `actions/checkout`) before invoking this action — the
6+
built commit is resolved with `git rev-parse HEAD` so the attestation
7+
records the revision that was actually built rather than `github.sha`,
8+
which on a tag push reflects the tag-pointed commit and may differ from
9+
the branch tip the release workflow checks out. The calling job must
10+
have `id-token: write`.
11+
12+
inputs:
13+
image:
14+
description: 'Full image reference (registry/repo:tag) to sign by digest.'
15+
required: true
16+
workflow-path:
17+
description: 'Path to the workflow file (repo-relative) that triggered the build.'
18+
required: true
19+
run-started-at:
20+
description: >-
21+
ISO-8601 workflow run start time (typically
22+
`github.run_started_at` from the caller workflow). Recorded as
23+
`runDetails.metadata.startedOn` in the SLSA provenance predicate.
24+
If empty, the action falls back to the time at which it began
25+
executing — `github.run_started_at` is reported empty in some
26+
edge cases and `required: true` on a composite-action input
27+
does not reject empty strings.
28+
required: true
29+
30+
runs:
31+
using: "composite"
32+
steps:
33+
- name: Capture fallback start timestamp
34+
id: start
35+
shell: bash
36+
run: |
37+
echo "STARTED_ON=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> "$GITHUB_OUTPUT"
38+
39+
- name: Install cosign
40+
uses: sigstore/cosign-installer@v3
41+
42+
- name: Install crane
43+
uses: imjasonh/setup-crane@v0.5
44+
45+
- name: Resolve image digest
46+
id: digest
47+
shell: bash
48+
env:
49+
IMAGE: ${{ inputs.image }}
50+
run: |
51+
set -euo pipefail
52+
DIGEST="$(crane digest "${IMAGE}")"
53+
REPO="${IMAGE%:*}"
54+
REF="${REPO}@${DIGEST}"
55+
echo "Resolved ${IMAGE} -> ${REF}"
56+
echo "REF=${REF}" >> "$GITHUB_OUTPUT"
57+
echo "DIGEST=${DIGEST}" >> "$GITHUB_OUTPUT"
58+
59+
- name: Sign image with cosign (keyless)
60+
shell: bash
61+
env:
62+
REF: ${{ steps.digest.outputs.REF }}
63+
run: |
64+
set -euo pipefail
65+
cosign sign --yes "${REF}"
66+
67+
- name: Generate SLSA v1 provenance predicate
68+
shell: bash
69+
env:
70+
WORKFLOW_PATH: ${{ inputs.workflow-path }}
71+
STARTED_ON: ${{ inputs.run-started-at }}
72+
FALLBACK_STARTED_ON: ${{ steps.start.outputs.STARTED_ON }}
73+
run: |
74+
set -euo pipefail
75+
if [[ -z "${STARTED_ON:-}" ]]; then
76+
STARTED_ON="$FALLBACK_STARTED_ON"
77+
fi
78+
RESOLVED_GIT_COMMIT="$(git rev-parse HEAD)"
79+
export RESOLVED_GIT_COMMIT STARTED_ON
80+
python3 - <<'PY' > predicate.json
81+
import json
82+
import os
83+
84+
repo = os.environ["GITHUB_REPOSITORY"]
85+
commit = os.environ["RESOLVED_GIT_COMMIT"]
86+
run_id = os.environ["GITHUB_RUN_ID"]
87+
run_attempt = os.environ["GITHUB_RUN_ATTEMPT"]
88+
89+
predicate = {
90+
"buildDefinition": {
91+
"buildType": "https://github.com/opencost/opencost/build/workflow@v1",
92+
"externalParameters": {
93+
"workflow": {
94+
"ref": os.environ["GITHUB_REF"],
95+
"repository": f"https://github.com/{repo}",
96+
"path": os.environ["WORKFLOW_PATH"],
97+
}
98+
},
99+
"internalParameters": {},
100+
"resolvedDependencies": [
101+
{
102+
"uri": f"git+https://github.com/{repo}@{commit}",
103+
"digest": {"gitCommit": commit},
104+
}
105+
],
106+
},
107+
"runDetails": {
108+
"builder": {
109+
"id": f"https://github.com/{repo}/actions/runs/{run_id}",
110+
},
111+
"metadata": {
112+
"invocationId": f"https://github.com/{repo}/actions/runs/{run_id}/attempts/{run_attempt}",
113+
"startedOn": os.environ["STARTED_ON"],
114+
},
115+
},
116+
}
117+
print(json.dumps(predicate, indent=2))
118+
PY
119+
120+
- name: Attest SLSA provenance with cosign
121+
shell: bash
122+
env:
123+
REF: ${{ steps.digest.outputs.REF }}
124+
run: |
125+
set -euo pipefail
126+
cosign attest --yes \
127+
--predicate predicate.json \
128+
--type slsaprovenance1 \
129+
"${REF}"

.github/dependabot.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,18 @@ updates:
55
directory: "/" # Location of package manifests
66
schedule:
77
interval: "weekly"
8+
- package-ecosystem: "gomod"
9+
directory: "/core" # Location of package manifests
10+
schedule:
11+
interval: "weekly"
12+
- package-ecosystem: "gomod"
13+
directory: "/modules/collector-source" # Location of package manifests
14+
schedule:
15+
interval: "weekly"
16+
- package-ecosystem: "gomod"
17+
directory: "/modules/prometheus-source" # Location of package manifests
18+
schedule:
19+
interval: "weekly"
820

921
# Dependencies listed in .github/workflows/*.yml
1022
- package-ecosystem: "github-actions"

.github/workflows/auto_label_issues.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ on:
44
issues:
55
types: [opened]
66

7+
permissions: {}
8+
79
jobs:
810
automate-issues-labels:
911
runs-on: ubuntu-latest

.github/workflows/build-and-publish-develop.yml

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ concurrency:
1010
group: build-opencost-develop
1111
cancel-in-progress: false
1212

13+
permissions: {}
14+
1315
env:
1416
# Use docker.io for Docker Hub if empty
1517
REGISTRY: ghcr.io
@@ -21,18 +23,24 @@ jobs:
2123
permissions:
2224
contents: read
2325
packages: write
26+
id-token: write
2427
steps:
2528
- name: Checkout Repo
26-
uses: actions/checkout@v4
29+
uses: actions/checkout@v6.0.2
30+
with:
31+
ref: ${{ github.event.workflow_run.head_sha }}
2732
- name: Set SHA
2833
id: sha
2934
run: |
3035
echo "OC_SHORTHASH=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
3136
3237
- name: Set OpenCost Image Tags
3338
id: tags
39+
env:
40+
REPO: ${{ github.repository_owner }}
41+
SHORTHASH: ${{ steps.sha.outputs.OC_SHORTHASH }}
3442
run: |
35-
echo "IMAGE_TAG=ghcr.io/${{ github.repository_owner }}/opencost:develop-${{ steps.sha.outputs.OC_SHORTHASH }}" >> $GITHUB_OUTPUT
43+
echo "IMAGE_TAG=ghcr.io/$REPO/opencost:develop-$SHORTHASH" >> $GITHUB_OUTPUT
3644
3745
- name: Build and publish container
3846
uses: ./.github/actions/build-container
@@ -43,15 +51,22 @@ jobs:
4351
release_version: develop-${{ steps.sha.outputs.OC_SHORTHASH }}
4452

4553
- name: Install crane
46-
uses: imjasonh/setup-crane@v0.4
54+
uses: imjasonh/setup-crane@v0.5
4755

4856
- name: Tag and push latest image
57+
env:
58+
IMAGE_TAG: ${{ steps.tags.outputs.IMAGE_TAG }}
4959
run: |
5060
# Extract the repository part (everything before the last colon)
51-
REPO=$(echo "${{ steps.tags.outputs.IMAGE_TAG }}" | sed 's/:.*$//')
61+
REPO=$(echo "$IMAGE_TAG" | sed 's/:.*$//')
5262
# Create the new tag
5363
NEW_TAG="${REPO}:develop-latest"
54-
echo "Copying ${{ steps.tags.outputs.IMAGE_TAG }} to ${NEW_TAG}"
55-
crane copy "${{ steps.tags.outputs.IMAGE_TAG }}" "${NEW_TAG}"
56-
64+
echo "Copying $IMAGE_TAG to ${NEW_TAG}"
65+
crane copy "$IMAGE_TAG" "${NEW_TAG}"
5766
67+
- name: Sign image and attest SLSA provenance
68+
uses: ./.github/actions/sign-image
69+
with:
70+
image: ${{ steps.tags.outputs.IMAGE_TAG }}
71+
workflow-path: .github/workflows/build-and-publish-develop.yml
72+
run-started-at: ${{ github.run_started_at }}

.github/workflows/build-and-publish-release.yml

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ on:
1010
description: "Version of the release"
1111
required: true
1212

13+
permissions: {}
14+
1315
concurrency:
1416
group: build-opencost
1517
cancel-in-progress: true
@@ -24,19 +26,22 @@ jobs:
2426
permissions:
2527
contents: read
2628
packages: write
29+
id-token: write
2730
steps:
2831
- name: Get Version From Tag
2932
id: tag
30-
if: ${{ github.event_name }} == 'push'
33+
if: ${{ github.event_name == 'push' }}
3134
run: |
3235
echo "TRIGGERED_TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
3336
3437
- name: Determine Version Number
3538
id: version_number
39+
env:
40+
RELEASE_VERSION: ${{ inputs.release_version }}
3641
run: |
3742
if [ -z "${TRIGGERED_TAG}" ];
3843
then
39-
version=${{ inputs.release_version }}
44+
version=$RELEASE_VERSION
4045
else
4146
version=$TRIGGERED_TAG
4247
fi
@@ -48,17 +53,20 @@ jobs:
4853
fi
4954
5055
- name: Show Input Values
56+
env:
57+
RELEASE_VERSION: ${{ inputs.release_version }}
5158
run: |
52-
echo "release version: ${{ inputs.release_version }}"
59+
echo "release version: $RELEASE_VERSION"
5360
5461
- name: Make Branch Name
5562
id: branch
63+
env:
64+
RELEASE_VERSION: ${{ steps.version_number.outputs.RELEASE_VERSION }}
5665
run: |
57-
VERSION_NUMBER=${{ steps.version_number.outputs.RELEASE_VERSION }}
58-
echo "BRANCH_NAME=v${VERSION_NUMBER%.*}" >> $GITHUB_OUTPUT
66+
echo "BRANCH_NAME=v${RELEASE_VERSION%.*}" >> $GITHUB_OUTPUT
5967
6068
- name: Checkout Repo
61-
uses: actions/checkout@v4
69+
uses: actions/checkout@v6.0.2
6270
with:
6371
ref: '${{ steps.branch.outputs.BRANCH_NAME }}'
6472

@@ -69,10 +77,14 @@ jobs:
6977
7078
- name: Set OpenCost Image Tags
7179
id: tags
80+
env:
81+
REPO_OWNER: ${{ github.repository_owner }}
82+
RELEASE_VERSION: ${{ steps.version_number.outputs.RELEASE_VERSION }}
83+
OC_SHORTHASH: ${{ steps.sha.outputs.OC_SHORTHASH }}
7284
run: |
73-
echo "IMAGE_TAG=ghcr.io/${{ github.repository_owner }}/opencost:${{ steps.sha.outputs.OC_SHORTHASH }}" >> $GITHUB_OUTPUT
74-
echo "IMAGE_TAG_LATEST=ghcr.io/${{ github.repository_owner }}/opencost:latest" >> $GITHUB_OUTPUT
75-
echo "IMAGE_TAG_VERSION=ghcr.io/${{ github.repository_owner }}/opencost:${{ steps.version_number.outputs.RELEASE_VERSION }}" >> $GITHUB_OUTPUT
85+
echo "IMAGE_TAG=ghcr.io/$REPO_OWNER/opencost:$OC_SHORTHASH" >> $GITHUB_OUTPUT
86+
echo "IMAGE_TAG_LATEST=ghcr.io/$REPO_OWNER/opencost:latest" >> $GITHUB_OUTPUT
87+
echo "IMAGE_TAG_VERSION=ghcr.io/$REPO_OWNER/opencost:$RELEASE_VERSION" >> $GITHUB_OUTPUT
7688
7789
- name: Build and publish container
7890
uses: ./.github/actions/build-container
@@ -83,17 +95,31 @@ jobs:
8395
release_version: ${{ steps.version_number.outputs.RELEASE_VERSION }}
8496

8597
- name: Log into registry ${{ env.REGISTRY }}
86-
uses: docker/login-action@v3
98+
uses: docker/login-action@v4
8799
with:
88100
registry: ${{ env.REGISTRY }}
89101
username: ${{ github.actor }}
90102
password: ${{ secrets.GITHUB_TOKEN }}
91103

92104
- name: Install crane
93-
uses: imjasonh/setup-crane@v0.4
105+
uses: imjasonh/setup-crane@v0.5
94106

95107
- name: Copy tags
108+
env:
109+
IMAGE_TAG: ${{ steps.tags.outputs.IMAGE_TAG }}
110+
IMAGE_TAG_LATEST: ${{ steps.tags.outputs.IMAGE_TAG_LATEST }}
111+
IMAGE_TAG_VERSION: ${{ steps.tags.outputs.IMAGE_TAG_VERSION }}
96112
run: |
97-
crane copy '${{ steps.tags.outputs.IMAGE_TAG }}' '${{ steps.tags.outputs.IMAGE_TAG_LATEST }}'
98-
crane copy '${{ steps.tags.outputs.IMAGE_TAG }}' '${{ steps.tags.outputs.IMAGE_TAG_VERSION }}'
113+
crane copy "$IMAGE_TAG" "$IMAGE_TAG_LATEST"
114+
crane copy "$IMAGE_TAG" "$IMAGE_TAG_VERSION"
99115
116+
- name: Sign image and attest SLSA provenance
117+
# Only sign tag-triggered releases; workflow_dispatch runs produce a
118+
# non-tag GITHUB_REF, so the Fulcio certificate identity would not
119+
# match the `refs/tags/vX.Y.Z` pattern documented in SECURITY.md.
120+
if: github.event_name == 'push'
121+
uses: ./.github/actions/sign-image
122+
with:
123+
image: ${{ steps.tags.outputs.IMAGE_TAG_VERSION }}
124+
workflow-path: .github/workflows/build-and-publish-release.yml
125+
run-started-at: ${{ github.run_started_at }}

0 commit comments

Comments
 (0)