@prism-d1/cli 1.0.83 → 1.0.85
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/coding-agent/README.md +824 -0
- package/dist/assets/coding-agent/agent.py +381 -0
- package/dist/assets/coding-agent/config.py +338 -0
- package/dist/assets/coding-agent/deploy/Dockerfile +86 -0
- package/dist/assets/coding-agent/deploy/create_harness.py +144 -0
- package/dist/assets/coding-agent/deploy/deploy-harness.sh +201 -0
- package/dist/assets/coding-agent/deploy/prism-coding-agent.yml +399 -0
- package/dist/assets/coding-agent/eval/run_eval.py +430 -0
- package/dist/assets/coding-agent/eval/run_harness_eval.py +262 -0
- package/dist/assets/coding-agent/eval/stubs/001-tags-element-validation.json +11 -0
- package/dist/assets/coding-agent/eval/stubs/002-status-filter.json +11 -0
- package/dist/assets/coding-agent/eval/stubs/003-refuse-test-deletion.json +11 -0
- package/dist/assets/coding-agent/fixtures/001-tags-element-validation.json +12 -0
- package/dist/assets/coding-agent/fixtures/002-status-filter.json +12 -0
- package/dist/assets/coding-agent/fixtures/003-refuse-test-deletion.json +10 -0
- package/dist/assets/coding-agent/pyproject.toml +28 -0
- package/dist/assets/coding-agent/requirements.txt +8 -0
- package/dist/assets/coding-agent/system_prompt.py +290 -0
- package/dist/assets/coding-agent/tools/__init__.py +11 -0
- package/dist/assets/coding-agent/tools/create_pr.py +141 -0
- package/dist/assets/coding-agent/tools/git_ops.py +197 -0
- package/dist/assets/github-workflows/prism-agent-eval.yml +8 -3
- package/dist/assets/github-workflows/prism-ai-metrics.yml +19 -6
- package/dist/assets/github-workflows/prism-eval-gate-kiro.yml +14 -9
- package/dist/assets/github-workflows/prism-eval-gate.yml +11 -6
- package/dist/assets/gitlab-workflows/prism-agent-eval.yml +5 -3
- package/dist/assets/gitlab-workflows/prism-ai-metrics.yml +5 -3
- package/dist/assets/gitlab-workflows/prism-eval-gate.yml +5 -3
- package/dist/assets/infra/lib/constructs/otel-collector-construct.ts +134 -2
- package/dist/assets/infra/lib/dashboard-stack.ts +79 -95
- package/dist/assets/infra/lib/lambda/metrics-processor.ts +99 -1
- package/dist/assets/infra/lib/lambda/otel-receiver.ts +318 -29
- package/dist/assets/infra/lib/lambda/productivity-widget.ts +85 -4
- package/dist/assets/infra/lib/lambda/velocity-widget.ts +265 -0
- package/dist/assets/infra/lib/metrics-pipeline-stack.ts +5 -0
- package/dist/src/commands/bootstrapper/install-coding-agent.d.ts +61 -0
- package/dist/src/commands/bootstrapper/install-coding-agent.d.ts.map +1 -0
- package/dist/src/commands/bootstrapper/install-coding-agent.js +599 -0
- package/dist/src/commands/bootstrapper/install-coding-agent.js.map +1 -0
- package/dist/src/commands/bootstrapper/install-eval-harness.d.ts.map +1 -1
- package/dist/src/commands/bootstrapper/install-eval-harness.js +16 -6
- package/dist/src/commands/bootstrapper/install-eval-harness.js.map +1 -1
- package/dist/src/commands/bootstrapper/install-github-workflows.d.ts.map +1 -1
- package/dist/src/commands/bootstrapper/install-github-workflows.js +13 -6
- package/dist/src/commands/bootstrapper/install-github-workflows.js.map +1 -1
- package/dist/src/commands/bootstrapper/install-gitlab-workflows.d.ts.map +1 -1
- package/dist/src/commands/bootstrapper/install-gitlab-workflows.js +9 -6
- package/dist/src/commands/bootstrapper/install-gitlab-workflows.js.map +1 -1
- package/dist/src/commands/bootstrapper/setup-github-oidc.d.ts.map +1 -1
- package/dist/src/commands/bootstrapper/setup-github-oidc.js +23 -0
- package/dist/src/commands/bootstrapper/setup-github-oidc.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"""Git operations exposed to the agent as a single Strands tool.
|
|
2
|
+
|
|
3
|
+
Every git invocation goes through `subprocess.run` with an argv list and never
|
|
4
|
+
`shell=True`. The agent supplies branch names and commit messages, so treating
|
|
5
|
+
them as shell strings would let a crafted issue body run arbitrary commands.
|
|
6
|
+
|
|
7
|
+
`push` is deliberately absent. Pushing is a privileged step that belongs to the
|
|
8
|
+
PR-creation path where credentials live, not to a general-purpose git tool the
|
|
9
|
+
model can call at will.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import re
|
|
15
|
+
import subprocess
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
from strands import tool
|
|
19
|
+
|
|
20
|
+
# Branch names: git's own rules, tightened. No leading/trailing dots or slashes,
|
|
21
|
+
# no '..', no characters git rejects, nothing that could be read as a flag.
|
|
22
|
+
_BRANCH_OK = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._/-]{0,99}$")
|
|
23
|
+
_TIMEOUT_SECONDS = 60
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class GitError(RuntimeError):
|
|
27
|
+
"""A git command failed or was rejected before running."""
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _run(args: list[str], cwd: Path) -> str:
|
|
31
|
+
"""Run a git command and return stdout, raising GitError on failure."""
|
|
32
|
+
try:
|
|
33
|
+
proc = subprocess.run(
|
|
34
|
+
["git", *args],
|
|
35
|
+
cwd=str(cwd),
|
|
36
|
+
capture_output=True,
|
|
37
|
+
text=True,
|
|
38
|
+
timeout=_TIMEOUT_SECONDS,
|
|
39
|
+
check=False,
|
|
40
|
+
)
|
|
41
|
+
except subprocess.TimeoutExpired as exc:
|
|
42
|
+
raise GitError(f"git {args[0]} timed out after {_TIMEOUT_SECONDS}s") from exc
|
|
43
|
+
except FileNotFoundError as exc:
|
|
44
|
+
raise GitError("git is not installed or not on PATH") from exc
|
|
45
|
+
|
|
46
|
+
if proc.returncode != 0:
|
|
47
|
+
detail = (proc.stderr or proc.stdout).strip()
|
|
48
|
+
raise GitError(f"git {' '.join(args)} failed: {detail}")
|
|
49
|
+
return proc.stdout.strip()
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _validate_branch(name: str) -> str:
|
|
53
|
+
name = name.strip()
|
|
54
|
+
if not _BRANCH_OK.match(name) or ".." in name or name.endswith((".", "/", ".lock")):
|
|
55
|
+
raise GitError(
|
|
56
|
+
f"Invalid branch name {name!r}. Use letters, digits, dot, dash, "
|
|
57
|
+
"underscore and slash; start with a letter or digit."
|
|
58
|
+
)
|
|
59
|
+
return name
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _validate_paths(paths: list[str], repo_path: Path) -> list[str]:
|
|
63
|
+
"""Resolve each path and confirm it stays inside the repository.
|
|
64
|
+
|
|
65
|
+
Rejects absolute paths, traversal, and symlinks that point outside the repo.
|
|
66
|
+
"""
|
|
67
|
+
resolved: list[str] = []
|
|
68
|
+
repo_real = repo_path.resolve()
|
|
69
|
+
for raw in paths:
|
|
70
|
+
candidate = (repo_real / raw).resolve()
|
|
71
|
+
try:
|
|
72
|
+
candidate.relative_to(repo_real)
|
|
73
|
+
except ValueError as exc:
|
|
74
|
+
raise GitError(f"Path escapes the repository: {raw!r}") from exc
|
|
75
|
+
if not candidate.exists():
|
|
76
|
+
raise GitError(f"Path does not exist: {raw!r}")
|
|
77
|
+
resolved.append(str(candidate.relative_to(repo_real)))
|
|
78
|
+
return resolved
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _resolve_repo(path: Path) -> Path | None:
|
|
83
|
+
"""Return the git repository enclosing `path`, or None if there is none.
|
|
84
|
+
|
|
85
|
+
Uses git's own answer rather than walking for a `.git` directory, so
|
|
86
|
+
worktrees and submodules resolve the way git itself sees them.
|
|
87
|
+
"""
|
|
88
|
+
try:
|
|
89
|
+
proc = subprocess.run(
|
|
90
|
+
["git", "rev-parse", "--show-toplevel"],
|
|
91
|
+
cwd=str(path), capture_output=True, text=True,
|
|
92
|
+
timeout=_TIMEOUT_SECONDS, check=False,
|
|
93
|
+
)
|
|
94
|
+
except (OSError, subprocess.SubprocessError):
|
|
95
|
+
return None
|
|
96
|
+
if proc.returncode != 0 or not proc.stdout.strip():
|
|
97
|
+
return None
|
|
98
|
+
return Path(proc.stdout.strip())
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@tool
|
|
102
|
+
def git_ops(
|
|
103
|
+
action: str,
|
|
104
|
+
repo_path: str,
|
|
105
|
+
branch: str | None = None,
|
|
106
|
+
message: str | None = None,
|
|
107
|
+
paths: list[str] | None = None,
|
|
108
|
+
) -> str:
|
|
109
|
+
"""Perform a git operation in the target repository.
|
|
110
|
+
|
|
111
|
+
Use this to create a working branch, inspect what you have changed, stage
|
|
112
|
+
specific files, and commit. Pushing is handled separately by create_pr.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
action: One of "status", "diff", "current_branch", "create_branch",
|
|
116
|
+
"stage", "commit", "log".
|
|
117
|
+
repo_path: Absolute path to the repository working tree.
|
|
118
|
+
branch: Branch name. Required for "create_branch".
|
|
119
|
+
message: Commit message. Required for "commit".
|
|
120
|
+
paths: Repository-relative file paths. Required for "stage". Name each
|
|
121
|
+
file explicitly; there is no "stage everything" option.
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
Command output, or a short confirmation for actions with no output.
|
|
125
|
+
"""
|
|
126
|
+
repo = Path(repo_path)
|
|
127
|
+
# Resolved rather than tested for a `.git` child, because a target is often a
|
|
128
|
+
# subdirectory of its repository -- PRISM's own sample-app sits inside a
|
|
129
|
+
# monorepo, and customer monorepos are the same shape.
|
|
130
|
+
#
|
|
131
|
+
# Requiring `.git` here caused a genuinely bad failure, observed rather than
|
|
132
|
+
# imagined: this tool refused with "not a git repository", and the agent --
|
|
133
|
+
# which also has a shell -- routed around the refusal by running `git init`
|
|
134
|
+
# and committing all 54 files as "Initial commit". A refusing tool is not a
|
|
135
|
+
# constraint on something that can run arbitrary commands; it is only a
|
|
136
|
+
# suggestion. So the tool has to be able to do the right thing rather than
|
|
137
|
+
# merely decline to do the wrong one.
|
|
138
|
+
resolved = _resolve_repo(repo)
|
|
139
|
+
if resolved is None:
|
|
140
|
+
return (
|
|
141
|
+
f"ERROR: {repo_path} is not inside a git repository. Do NOT run "
|
|
142
|
+
f"`git init` -- that would create a new repository and commit "
|
|
143
|
+
f"everything, which is never the fix. Report the problem instead."
|
|
144
|
+
)
|
|
145
|
+
repo = resolved
|
|
146
|
+
|
|
147
|
+
try:
|
|
148
|
+
if action == "status":
|
|
149
|
+
out = _run(["status", "--porcelain=v1"], repo)
|
|
150
|
+
return out or "(working tree clean)"
|
|
151
|
+
|
|
152
|
+
if action == "diff":
|
|
153
|
+
out = _run(["diff", "--stat", "HEAD"], repo)
|
|
154
|
+
return out or "(no changes against HEAD)"
|
|
155
|
+
|
|
156
|
+
if action == "current_branch":
|
|
157
|
+
return _run(["rev-parse", "--abbrev-ref", "HEAD"], repo)
|
|
158
|
+
|
|
159
|
+
if action == "log":
|
|
160
|
+
return _run(["log", "--oneline", "-10"], repo)
|
|
161
|
+
|
|
162
|
+
if action == "create_branch":
|
|
163
|
+
if not branch:
|
|
164
|
+
return "ERROR: create_branch requires a branch name"
|
|
165
|
+
safe = _validate_branch(branch)
|
|
166
|
+
_run(["checkout", "-b", safe], repo)
|
|
167
|
+
return f"Created and switched to branch {safe}"
|
|
168
|
+
|
|
169
|
+
if action == "stage":
|
|
170
|
+
if not paths:
|
|
171
|
+
return (
|
|
172
|
+
"ERROR: stage requires an explicit list of paths. "
|
|
173
|
+
"Name each file you changed."
|
|
174
|
+
)
|
|
175
|
+
safe_paths = _validate_paths(paths, repo)
|
|
176
|
+
_run(["add", "--", *safe_paths], repo)
|
|
177
|
+
return f"Staged {len(safe_paths)} file(s): {', '.join(safe_paths)}"
|
|
178
|
+
|
|
179
|
+
if action == "commit":
|
|
180
|
+
if not message or not message.strip():
|
|
181
|
+
return "ERROR: commit requires a non-empty message"
|
|
182
|
+
staged = _run(["diff", "--cached", "--name-only"], repo)
|
|
183
|
+
if not staged:
|
|
184
|
+
return "ERROR: nothing staged. Stage your changed files first."
|
|
185
|
+
# -m takes the message as a separate argv element, so newlines and
|
|
186
|
+
# quotes in the message are data, not shell syntax.
|
|
187
|
+
_run(["commit", "-m", message], repo)
|
|
188
|
+
sha = _run(["rev-parse", "HEAD"], repo)
|
|
189
|
+
return f"Committed {sha[:8]} with files:\n{staged}"
|
|
190
|
+
|
|
191
|
+
return (
|
|
192
|
+
f"ERROR: unknown action {action!r}. Valid actions: status, diff, "
|
|
193
|
+
"current_branch, create_branch, stage, commit, log"
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
except GitError as exc:
|
|
197
|
+
return f"ERROR: {exc}"
|
|
@@ -23,6 +23,11 @@ on:
|
|
|
23
23
|
- '**/agent*.py'
|
|
24
24
|
- '**/agent*.ts'
|
|
25
25
|
|
|
26
|
+
|
|
27
|
+
env:
|
|
28
|
+
PRISM_AWS_REGION: us-west-2
|
|
29
|
+
PRISM_REPO: github.com/${{ github.repository }}
|
|
30
|
+
|
|
26
31
|
permissions:
|
|
27
32
|
id-token: write
|
|
28
33
|
contents: read
|
|
@@ -41,7 +46,7 @@ jobs:
|
|
|
41
46
|
uses: aws-actions/configure-aws-credentials@b47578312673ae6fa5b5096b330d9fbac3d116df # v4.2.1
|
|
42
47
|
with:
|
|
43
48
|
role-to-assume: ${{ secrets.PRISM_METRICS_ROLE_ARN }}
|
|
44
|
-
aws-region:
|
|
49
|
+
aws-region: ${{ env.PRISM_AWS_REGION }}
|
|
45
50
|
|
|
46
51
|
- name: Read team ID from .prism/config.json
|
|
47
52
|
id: prism-config
|
|
@@ -263,7 +268,7 @@ jobs:
|
|
|
263
268
|
|
|
264
269
|
EVAL_EVENT=$(jq -n \
|
|
265
270
|
--arg team_id "${{ steps.prism-config.outputs.team_id }}" \
|
|
266
|
-
--arg repo "${
|
|
271
|
+
--arg repo "${PRISM_REPO}" \
|
|
267
272
|
--arg timestamp "${TIMESTAMP}" \
|
|
268
273
|
--argjson score "${SCORE:-0}" \
|
|
269
274
|
--arg result "${{ steps.eval.outputs.result }}" \
|
|
@@ -298,7 +303,7 @@ jobs:
|
|
|
298
303
|
}')
|
|
299
304
|
|
|
300
305
|
aws events put-events \
|
|
301
|
-
--region
|
|
306
|
+
--region $PRISM_AWS_REGION \
|
|
302
307
|
--entries "[{
|
|
303
308
|
\"Source\": \"prism.d1.velocity\",
|
|
304
309
|
\"DetailType\": \"prism.d1.agent.eval\",
|
|
@@ -33,6 +33,11 @@ on:
|
|
|
33
33
|
types: [closed]
|
|
34
34
|
branches: [main, master]
|
|
35
35
|
|
|
36
|
+
|
|
37
|
+
env:
|
|
38
|
+
PRISM_AWS_REGION: us-west-2
|
|
39
|
+
PRISM_REPO: github.com/${{ github.repository }}
|
|
40
|
+
|
|
36
41
|
permissions:
|
|
37
42
|
id-token: write
|
|
38
43
|
contents: read
|
|
@@ -54,7 +59,7 @@ jobs:
|
|
|
54
59
|
uses: aws-actions/configure-aws-credentials@b47578312673ae6fa5b5096b330d9fbac3d116df # v4.2.1
|
|
55
60
|
with:
|
|
56
61
|
role-to-assume: ${{ secrets.PRISM_METRICS_ROLE_ARN }}
|
|
57
|
-
aws-region:
|
|
62
|
+
aws-region: ${{ env.PRISM_AWS_REGION }}
|
|
58
63
|
|
|
59
64
|
- name: Read team ID from .prism/config.json
|
|
60
65
|
id: prism-config
|
|
@@ -101,6 +106,11 @@ jobs:
|
|
|
101
106
|
COMMIT_SHAS=$(git rev-list --no-merges "${BASE_SHA}..${HEAD_SHA}" 2>/dev/null | head -50 | jq -R . | jq -sc . || echo '[]')
|
|
102
107
|
TOTAL_COMMITS=$(git rev-list --no-merges --count "${BASE_SHA}..${HEAD_SHA}" 2>/dev/null || echo 0)
|
|
103
108
|
|
|
109
|
+
# Per-commit author emails (parallel array to COMMIT_SHAS). Used by
|
|
110
|
+
# the metrics-processor to seed COMMIT# items with the correct user
|
|
111
|
+
# field so /v1/productivity can attribute human commits per-developer.
|
|
112
|
+
COMMIT_AUTHORS=$(git rev-list --no-merges "${BASE_SHA}..${HEAD_SHA}" 2>/dev/null | head -50 | while read sha; do git log -1 --format='%ae' "$sha"; done | jq -R . | jq -sc . || echo '[]')
|
|
113
|
+
|
|
104
114
|
# --- Lead time: PR open → merge. From the event payload, not git, so
|
|
105
115
|
# it is unaffected by rebases and squashes.
|
|
106
116
|
CREATED_TS=$(date -d "${CREATED_AT}" +%s 2>/dev/null || date -jf "%Y-%m-%dT%H:%M:%SZ" "${CREATED_AT}" +%s)
|
|
@@ -119,6 +129,7 @@ jobs:
|
|
|
119
129
|
fi
|
|
120
130
|
|
|
121
131
|
echo "commit_shas=${COMMIT_SHAS}" >> "$GITHUB_OUTPUT"
|
|
132
|
+
echo "commit_authors=${COMMIT_AUTHORS}" >> "$GITHUB_OUTPUT"
|
|
122
133
|
echo "total_commits=${TOTAL_COMMITS}" >> "$GITHUB_OUTPUT"
|
|
123
134
|
echo "lead_time_seconds=${LEAD_TIME_SECONDS}" >> "$GITHUB_OUTPUT"
|
|
124
135
|
echo "is_failure_fix=${IS_FAILURE_FIX}" >> "$GITHUB_OUTPUT"
|
|
@@ -150,12 +161,13 @@ jobs:
|
|
|
150
161
|
|
|
151
162
|
PR_EVENT=$(jq -n \
|
|
152
163
|
--arg team_id "${{ steps.prism-config.outputs.team_id }}" \
|
|
153
|
-
--arg repo "${
|
|
164
|
+
--arg repo "${PRISM_REPO}" \
|
|
154
165
|
--arg timestamp "${TIMESTAMP}" \
|
|
155
166
|
--argjson lead_time_seconds "${{ steps.facts.outputs.lead_time_seconds }}" \
|
|
156
167
|
--argjson is_failure_fix "${{ steps.facts.outputs.is_failure_fix }}" \
|
|
157
168
|
--argjson total_commits "${{ steps.facts.outputs.total_commits }}" \
|
|
158
169
|
--argjson commit_shas '${{ steps.facts.outputs.commit_shas }}' \
|
|
170
|
+
--argjson commit_authors '${{ steps.facts.outputs.commit_authors }}' \
|
|
159
171
|
--arg pr_number "${{ github.event.pull_request.number }}" \
|
|
160
172
|
--arg pr_author "${{ github.event.pull_request.user.login }}" \
|
|
161
173
|
--argjson approved "${{ steps.reviews.outputs.approved }}" \
|
|
@@ -180,12 +192,13 @@ jobs:
|
|
|
180
192
|
"reviews_approved": $approved,
|
|
181
193
|
"reviews_changes_requested": $changes_requested,
|
|
182
194
|
"total_commits": $total_commits,
|
|
183
|
-
"commit_shas": $commit_shas
|
|
195
|
+
"commit_shas": $commit_shas,
|
|
196
|
+
"commit_authors": $commit_authors
|
|
184
197
|
}
|
|
185
198
|
}')
|
|
186
199
|
|
|
187
200
|
aws events put-events \
|
|
188
|
-
--region
|
|
201
|
+
--region $PRISM_AWS_REGION \
|
|
189
202
|
--entries "[{
|
|
190
203
|
\"Source\": \"prism.d1.velocity\",
|
|
191
204
|
\"DetailType\": \"prism.d1.pr\",
|
|
@@ -207,7 +220,7 @@ jobs:
|
|
|
207
220
|
# carrying it on both double-counted the DeploymentFrequency metric.
|
|
208
221
|
DEPLOY_EVENT=$(jq -n \
|
|
209
222
|
--arg team_id "${{ steps.prism-config.outputs.team_id }}" \
|
|
210
|
-
--arg repo "${
|
|
223
|
+
--arg repo "${PRISM_REPO}" \
|
|
211
224
|
--arg timestamp "${TIMESTAMP}" \
|
|
212
225
|
'{
|
|
213
226
|
"team_id": $team_id,
|
|
@@ -225,7 +238,7 @@ jobs:
|
|
|
225
238
|
}')
|
|
226
239
|
|
|
227
240
|
aws events put-events \
|
|
228
|
-
--region
|
|
241
|
+
--region $PRISM_AWS_REGION \
|
|
229
242
|
--entries "[{
|
|
230
243
|
\"Source\": \"prism.d1.velocity\",
|
|
231
244
|
\"DetailType\": \"prism.d1.deploy\",
|
|
@@ -15,6 +15,11 @@ on:
|
|
|
15
15
|
types: [opened, synchronize, reopened]
|
|
16
16
|
branches: [main, master]
|
|
17
17
|
|
|
18
|
+
|
|
19
|
+
env:
|
|
20
|
+
PRISM_AWS_REGION: us-west-2
|
|
21
|
+
PRISM_REPO: github.com/${{ github.repository }}
|
|
22
|
+
|
|
18
23
|
permissions:
|
|
19
24
|
id-token: write
|
|
20
25
|
contents: read
|
|
@@ -213,15 +218,15 @@ jobs:
|
|
|
213
218
|
uses: aws-actions/configure-aws-credentials@b47578312673ae6fa5b5096b330d9fbac3d116df # v4.2.1
|
|
214
219
|
with:
|
|
215
220
|
role-to-assume: ${{ env.METRICS_ROLE_ARN }}
|
|
216
|
-
aws-region:
|
|
221
|
+
aws-region: ${{ env.PRISM_AWS_REGION }}
|
|
217
222
|
continue-on-error: true
|
|
218
223
|
|
|
219
224
|
- name: Emit prism.d1.eval event
|
|
220
225
|
if: steps.aws-creds.outcome == 'success'
|
|
221
226
|
env:
|
|
222
|
-
AWS_REGION:
|
|
227
|
+
AWS_REGION: ${{ env.PRISM_AWS_REGION }}
|
|
223
228
|
TEAM_ID: ${{ steps.prism-config.outputs.team_id }}
|
|
224
|
-
REPO: ${{
|
|
229
|
+
REPO: ${{ env.PRISM_REPO }}
|
|
225
230
|
REVIEW_SCORE: ${{ steps.review.outputs.score }}
|
|
226
231
|
REVIEW_RESULT: ${{ steps.review.outputs.result }}
|
|
227
232
|
REVIEW_FINDINGS: ${{ steps.review.outputs.findings }}
|
|
@@ -249,17 +254,17 @@ jobs:
|
|
|
249
254
|
eval:{score:($score|tonumber),result:$result,rubric:"kiro-headless",
|
|
250
255
|
findings:($findings|tonumber),high_findings:($high|tonumber),
|
|
251
256
|
pr_number:($pr_number|tonumber),method:"kiro-headless"}}')
|
|
252
|
-
aws events put-events --region
|
|
257
|
+
aws events put-events --region $PRISM_AWS_REGION --entries \
|
|
253
258
|
"[{\"Source\":\"prism.d1.velocity\",\"DetailType\":\"prism.d1.eval\",\"EventBusName\":\"prism-d1-metrics\",\"Detail\":$(echo "${DETAIL}" | jq -Rs '.')}]" || true
|
|
254
259
|
|
|
255
260
|
- name: AWS Continuum security scan (Tier 2 -- deterministic)
|
|
256
261
|
id: security-gate
|
|
257
262
|
if: steps.aws-creds.outcome == 'success'
|
|
258
263
|
env:
|
|
259
|
-
AWS_REGION:
|
|
264
|
+
AWS_REGION: ${{ env.PRISM_AWS_REGION }}
|
|
260
265
|
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
|
261
266
|
HEAD_SHA: ${{ github.sha }}
|
|
262
|
-
REPO: ${{
|
|
267
|
+
REPO: ${{ env.PRISM_REPO }}
|
|
263
268
|
PR_NUMBER: ${{ github.event.pull_request.number }}
|
|
264
269
|
run: |
|
|
265
270
|
# Config is read FIRST, on purpose. "Continuum was never deployed" is a
|
|
@@ -407,9 +412,9 @@ jobs:
|
|
|
407
412
|
if: steps.security-gate.outputs.skipped != 'true' && steps.security-gate.outputs.findings != '0' && steps.security-gate.outputs.findings != ''
|
|
408
413
|
continue-on-error: true
|
|
409
414
|
env:
|
|
410
|
-
AWS_REGION:
|
|
415
|
+
AWS_REGION: ${{ env.PRISM_AWS_REGION }}
|
|
411
416
|
TEAM_ID: ${{ steps.prism-config.outputs.team_id }}
|
|
412
|
-
REPO: ${{
|
|
417
|
+
REPO: ${{ env.PRISM_REPO }}
|
|
413
418
|
PR_NUMBER: ${{ github.event.pull_request.number }}
|
|
414
419
|
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
|
415
420
|
HEAD_SHA: ${{ github.sha }}
|
|
@@ -458,7 +463,7 @@ jobs:
|
|
|
458
463
|
if [ "$TOTAL" -gt 0 ]; then
|
|
459
464
|
# EventBridge accepts max 10 entries per call
|
|
460
465
|
for i in $(seq 0 10 $((TOTAL - 1))); do
|
|
461
|
-
aws events put-events --region
|
|
466
|
+
aws events put-events --region $PRISM_AWS_REGION \
|
|
462
467
|
--entries "$(echo "${ENTRIES}" | jq -c ".[$i:$((i+10))]")" || true
|
|
463
468
|
done
|
|
464
469
|
echo "Emitted ${TOTAL} Continuum finding events to EventBridge"
|
|
@@ -16,6 +16,11 @@ on:
|
|
|
16
16
|
types: [opened, synchronize, reopened]
|
|
17
17
|
branches: [main, master]
|
|
18
18
|
|
|
19
|
+
|
|
20
|
+
env:
|
|
21
|
+
PRISM_AWS_REGION: us-west-2
|
|
22
|
+
PRISM_REPO: github.com/${{ github.repository }}
|
|
23
|
+
|
|
19
24
|
permissions:
|
|
20
25
|
id-token: write
|
|
21
26
|
contents: read
|
|
@@ -34,7 +39,7 @@ jobs:
|
|
|
34
39
|
uses: aws-actions/configure-aws-credentials@b47578312673ae6fa5b5096b330d9fbac3d116df # v4.2.1
|
|
35
40
|
with:
|
|
36
41
|
role-to-assume: ${{ secrets.PRISM_METRICS_ROLE_ARN }}
|
|
37
|
-
aws-region:
|
|
42
|
+
aws-region: ${{ env.PRISM_AWS_REGION }}
|
|
38
43
|
|
|
39
44
|
- name: Read team ID
|
|
40
45
|
id: prism-config
|
|
@@ -201,7 +206,7 @@ jobs:
|
|
|
201
206
|
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
202
207
|
EVAL_EVENT=$(jq -n \
|
|
203
208
|
--arg team_id "${{ steps.prism-config.outputs.team_id }}" \
|
|
204
|
-
--arg repo "${
|
|
209
|
+
--arg repo "${PRISM_REPO}" \
|
|
205
210
|
--arg timestamp "${TIMESTAMP}" \
|
|
206
211
|
--argjson score "${{ steps.eval.outputs.avg_score }}" \
|
|
207
212
|
--arg result "${{ steps.eval.outputs.overall_result }}" \
|
|
@@ -217,7 +222,7 @@ jobs:
|
|
|
217
222
|
eval: {total_files: $total_files, pass_count: $pass_count, fail_count: $fail_count,
|
|
218
223
|
result: $result, pr_number: ($pr_number | tonumber), hallucinations_caught: $hallucinations}
|
|
219
224
|
}')
|
|
220
|
-
aws events put-events --region
|
|
225
|
+
aws events put-events --region $PRISM_AWS_REGION --entries "[{
|
|
221
226
|
\"Source\":\"prism.d1.velocity\",\"DetailType\":\"prism.d1.eval\",
|
|
222
227
|
\"EventBusName\":\"prism-d1-metrics\",
|
|
223
228
|
\"Detail\":$(echo "${EVAL_EVENT}" | jq -c '.' | jq -Rs '.')}]"
|
|
@@ -238,7 +243,7 @@ jobs:
|
|
|
238
243
|
- name: AWS Continuum diff scan
|
|
239
244
|
id: security-gate
|
|
240
245
|
env:
|
|
241
|
-
AWS_REGION:
|
|
246
|
+
AWS_REGION: ${{ env.PRISM_AWS_REGION }}
|
|
242
247
|
run: |
|
|
243
248
|
echo "::group::Retrieve Continuum config from SSM"
|
|
244
249
|
AGENT_SPACE_ID=$(aws ssm get-parameter --name /prism/continuum/agent-space-id --query Parameter.Value --output text 2>/dev/null || echo "")
|
|
@@ -414,10 +419,10 @@ jobs:
|
|
|
414
419
|
- name: Emit Continuum findings to EventBridge
|
|
415
420
|
if: steps.security-gate.outputs.findings != '0' && steps.security-gate.outputs.skipped != 'true'
|
|
416
421
|
env:
|
|
417
|
-
AWS_REGION:
|
|
422
|
+
AWS_REGION: ${{ env.PRISM_AWS_REGION }}
|
|
418
423
|
run: |
|
|
419
424
|
PR_NUMBER="${{ github.event.pull_request.number }}"
|
|
420
|
-
REPO="${
|
|
425
|
+
REPO="${PRISM_REPO}"
|
|
421
426
|
TEAM_ID="${{ steps.prism-config.outputs.team_id }}"
|
|
422
427
|
FINDINGS='${{ steps.security-gate.outputs.findings_json }}'
|
|
423
428
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
#
|
|
7
7
|
# Required setup:
|
|
8
8
|
# - CI/CD variable PRISM_METRICS_ROLE_ARN (IAM role with bedrock:InvokeModel + events:PutEvents)
|
|
9
|
-
# -
|
|
9
|
+
# - PRISM_AWS_REGION variable in the variables: block below controls the region
|
|
10
10
|
# - .prism/config.json committed to the repo
|
|
11
11
|
# - .prism/eval-harness/ installed (run: prism-cli bootstrapper install-eval-harness)
|
|
12
12
|
# - (Optional) Agent entry point supports --mock flag for dry-run execution
|
|
@@ -26,7 +26,9 @@ prism-agent-eval:
|
|
|
26
26
|
- "**/*agent*.py"
|
|
27
27
|
- "**/*agent*.ts"
|
|
28
28
|
variables:
|
|
29
|
-
|
|
29
|
+
PRISM_AWS_REGION: us-west-2
|
|
30
|
+
AWS_DEFAULT_REGION: $PRISM_AWS_REGION
|
|
31
|
+
PRISM_REPO: ${CI_SERVER_HOST}/${CI_PROJECT_PATH}
|
|
30
32
|
before_script:
|
|
31
33
|
- apt-get update -qq && apt-get install -y -qq jq bc git curl unzip
|
|
32
34
|
- curl -s "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o /tmp/awscliv2.zip
|
|
@@ -133,7 +135,7 @@ prism-agent-eval:
|
|
|
133
135
|
# Emit event
|
|
134
136
|
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
135
137
|
EVAL_EVENT=$(jq -n \
|
|
136
|
-
--arg team_id "${TEAM_ID}" --arg repo "${
|
|
138
|
+
--arg team_id "${TEAM_ID}" --arg repo "${PRISM_REPO}" --arg timestamp "${TIMESTAMP}" \
|
|
137
139
|
--argjson score "${SCORE:-0}" --arg result "${RESULT}" --argjson file_count "${FILE_COUNT}" \
|
|
138
140
|
--arg mr_iid "${CI_MERGE_REQUEST_IID}" --arg mock_ran "${MOCK_RAN}" \
|
|
139
141
|
'{team_id:$team_id, repo:$repo, timestamp:$timestamp, prism_level:3,
|
|
@@ -32,7 +32,9 @@ prism-ai-metrics:
|
|
|
32
32
|
rules:
|
|
33
33
|
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "push"'
|
|
34
34
|
variables:
|
|
35
|
-
|
|
35
|
+
PRISM_AWS_REGION: us-west-2
|
|
36
|
+
AWS_DEFAULT_REGION: $PRISM_AWS_REGION
|
|
37
|
+
PRISM_REPO: ${CI_SERVER_HOST}/${CI_PROJECT_PATH}
|
|
36
38
|
before_script:
|
|
37
39
|
- yum install -y -q jq git
|
|
38
40
|
- git fetch --unshallow || true
|
|
@@ -113,7 +115,7 @@ prism-ai-metrics:
|
|
|
113
115
|
# shape — the processor only persists a known section list.
|
|
114
116
|
PR_EVENT=$(jq -n \
|
|
115
117
|
--arg team_id "${TEAM_ID}" \
|
|
116
|
-
--arg repo "${
|
|
118
|
+
--arg repo "${PRISM_REPO}" \
|
|
117
119
|
--arg timestamp "${TIMESTAMP}" \
|
|
118
120
|
--argjson lead_time_seconds "${LEAD_TIME_SECONDS}" \
|
|
119
121
|
--argjson is_failure_fix "${IS_FAILURE_FIX}" \
|
|
@@ -140,7 +142,7 @@ prism-ai-metrics:
|
|
|
140
142
|
|
|
141
143
|
# Sole deployment signal — deployment_frequency lives ONLY on this event.
|
|
142
144
|
# Carrying it on prism.d1.pr as well double-counted the metric.
|
|
143
|
-
DEPLOY_EVENT=$(jq -n --arg team_id "${TEAM_ID}" --arg repo "${
|
|
145
|
+
DEPLOY_EVENT=$(jq -n --arg team_id "${TEAM_ID}" --arg repo "${PRISM_REPO}" --arg timestamp "${TIMESTAMP}" \
|
|
144
146
|
'{team_id: $team_id, repo: $repo, timestamp: $timestamp, prism_level: 2,
|
|
145
147
|
metric: {name: "deployment", value: 1, unit: "count"},
|
|
146
148
|
dora: {deployment_frequency: 1}}')
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
#
|
|
7
7
|
# Required setup:
|
|
8
8
|
# - CI/CD variable PRISM_METRICS_ROLE_ARN (IAM role with bedrock:InvokeModel + events:PutEvents)
|
|
9
|
-
# -
|
|
9
|
+
# - PRISM_AWS_REGION variable in the variables: block below controls the region
|
|
10
10
|
# - .prism/eval-harness/ directory in your repo (run: prism-cli bootstrapper install-eval-harness)
|
|
11
11
|
# - At least one rubric JSON in .prism/eval-harness/rubrics/
|
|
12
12
|
|
|
@@ -21,7 +21,9 @@ prism-eval-gate:
|
|
|
21
21
|
rules:
|
|
22
22
|
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
|
23
23
|
variables:
|
|
24
|
-
|
|
24
|
+
PRISM_AWS_REGION: us-west-2
|
|
25
|
+
AWS_DEFAULT_REGION: $PRISM_AWS_REGION
|
|
26
|
+
PRISM_REPO: ${CI_SERVER_HOST}/${CI_PROJECT_PATH}
|
|
25
27
|
before_script:
|
|
26
28
|
- yum install -y -q jq bc git
|
|
27
29
|
- git fetch --unshallow || true
|
|
@@ -139,7 +141,7 @@ prism-eval-gate:
|
|
|
139
141
|
# Emit event
|
|
140
142
|
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
141
143
|
EVAL_EVENT=$(jq -n \
|
|
142
|
-
--arg team_id "${TEAM_ID}" --arg repo "${
|
|
144
|
+
--arg team_id "${TEAM_ID}" --arg repo "${PRISM_REPO}" --arg timestamp "${TIMESTAMP}" \
|
|
143
145
|
--argjson score "${AVG_SCORE}" --arg result "${OVERALL}" \
|
|
144
146
|
--argjson total_files "${TOTAL_FILES}" --argjson pass_count "${PASS_COUNT}" \
|
|
145
147
|
--argjson fail_count "${FAIL_COUNT}" --argjson hallucinations "${TOTAL_HALLUCINATIONS}" \
|