Skip to content

Commit 36bb83b

Browse files
committed
feat(api): Add obfuscation field to ChatCompletionChunk
Castiron-Internal-PR: openai/openai-python-internal#48 Castiron-Source-SHA: 1da516e7483ea031e228db8338990b552edbd3a1 Castiron-Public-Base-SHA: 2598d53
1 parent 2598d53 commit 36bb83b

11 files changed

Lines changed: 1839 additions & 10 deletions

File tree

.castiron.stats.yml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
schema_version: 1
2-
generation_id: 04cb977a-ba1d-438c-a56e-94f269e79218
3-
openapi_spec_hash: dd725fb7d43ceec7fb2de6f8713d14b6
4-
openapi_transformed_spec_hash: 10930179c5f116288e24e0c6fda46559
2+
generation_id: 14743cd4-a53e-4fed-ba72-d5e23592153e
3+
openapi_spec_hash: a99ded1ea34cf528a9cd5f064167f26a
4+
openapi_transformed_spec_hash: e24c9d9339620c3cce8bbdd80e9ef8ed
55
config_hash: 85382dd94c503b5d225adc7636a77c9f
6-
codegen_sha: 6e990f52e3cbdeaae602710a1b0f2a2c944a5c35
6+
codegen_sha: 66cd6dedd5d1b60732d891f911deb07347a8f068
7+
codegen_hash: 0e1cb892e3631438e55b55edd14899551f458be8d073e13d2c191730297562d6
8+
public_codegen_sha: 6356986f823c01fd602da9f64ef414c01db4619c
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# File generated from our OpenAPI spec by Castiron. See CONTRIBUTING.md for details.
2+
name: Castiron custom code comment
3+
4+
on:
5+
workflow_run:
6+
workflows: [Castiron custom code]
7+
types: [completed]
8+
9+
permissions: {}
10+
11+
concurrency:
12+
group: castiron-custom-code-comment-${{ github.event.workflow_run.head_repository.id }}-${{ github.event.workflow_run.head_branch }}
13+
cancel-in-progress: false
14+
15+
jobs:
16+
comment:
17+
name: Update custom-code comment
18+
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.path == '.github/workflows/castiron-custom-code.yml'
19+
runs-on: ubuntu-latest
20+
timeout-minutes: 5
21+
permissions:
22+
contents: read
23+
actions: read
24+
pull-requests: write
25+
steps:
26+
- name: Check out the trusted publisher
27+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
28+
with:
29+
ref: ${{ github.workflow_sha }}
30+
persist-credentials: false
31+
32+
- name: Download the completed run's report
33+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
34+
with:
35+
github-token: ${{ github.token }}
36+
run-id: ${{ github.event.workflow_run.id }}
37+
name: castiron-custom-code-${{ github.event.workflow_run.id }}-${{ github.event.workflow_run.run_attempt }}
38+
path: ${{ runner.temp }}/castiron-custom-code
39+
40+
- name: Validate report context
41+
id: context
42+
env:
43+
REPOSITORY: ${{ github.repository }}
44+
RUN_ID: ${{ github.event.workflow_run.id }}
45+
RUN_ATTEMPT: ${{ github.event.workflow_run.run_attempt }}
46+
run: |
47+
number=$(jq -er --arg repository "$REPOSITORY" --argjson run "$RUN_ID" \
48+
--argjson attempt "$RUN_ATTEMPT" \
49+
'select(.repository == $repository and .run == $run and .attempt == $attempt) | .pr | select(type == "number" and . > 0 and . == floor)' \
50+
"$RUNNER_TEMP/castiron-custom-code/context.json")
51+
printf 'number=%s\n' "$number" >> "$GITHUB_OUTPUT"
52+
53+
- name: Create or update the single report comment
54+
id: publish
55+
env:
56+
GH_TOKEN: ${{ github.token }}
57+
REPOSITORY: ${{ github.repository }}
58+
PR_NUMBER: ${{ steps.context.outputs.number }}
59+
RUN_ID: ${{ github.event.workflow_run.id }}
60+
RUN_ATTEMPT: ${{ github.event.workflow_run.run_attempt }}
61+
run: |
62+
python3 -I scripts/castiron/custom_code_report.py comment \
63+
--report "$RUNNER_TEMP/castiron-custom-code/report.json" \
64+
--repository "$REPOSITORY" --pr "$PR_NUMBER" --run-id "$RUN_ID" \
65+
--run-attempt "$RUN_ATTEMPT"
66+
67+
- name: Publish a trusted failure status
68+
if: always() && !cancelled() && steps.publish.outcome != 'success'
69+
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
70+
with:
71+
script: |
72+
const marker = '<!-- castiron:custom-code-report:v1 -->';
73+
const run = context.payload.workflow_run;
74+
if (run.event !== 'pull_request' || run.path !== '.github/workflows/castiron-custom-code.yml') return;
75+
const pulls = run.pull_requests?.length ? run.pull_requests : await github.paginate(github.rest.repos.listPullRequestsAssociatedWithCommit, {...context.repo, commit_sha: run.head_sha});
76+
for (const pull of pulls) {
77+
const {data: current} = await github.rest.pulls.get({...context.repo, pull_number: pull.number});
78+
if (current.state !== 'open' || current.head.sha !== run.head_sha) continue;
79+
const comments = await github.paginate(github.rest.issues.listComments, {...context.repo, issue_number: pull.number});
80+
const previous = comments.find(c => c.user?.type === 'Bot' && c.user?.login === 'github-actions[bot]' && c.body?.startsWith(marker));
81+
const prior = previous?.body?.match(/<!-- castiron:run:v1:(\d+):(\d+) -->/);
82+
if (prior && (Number(prior[1]) > run.id || (Number(prior[1]) === run.id && Number(prior[2]) > run.run_attempt))) continue;
83+
const url = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${run.id}`;
84+
const body = `${marker}\n\n## Castiron custom code\n\n⚠️ Report unavailable for \`${run.head_sha.slice(0, 12)}\`.\n\nThe report setup or validation failed. [Inspect the workflow run](${url}).\n\n<!-- castiron:run:v1:${run.id}:${run.run_attempt} -->`;
85+
if (previous) await github.rest.issues.updateComment({...context.repo, comment_id: previous.id, body});
86+
else await github.rest.issues.createComment({...context.repo, issue_number: pull.number, body});
87+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# File generated from our OpenAPI spec by Castiron. See CONTRIBUTING.md for details.
2+
name: Castiron custom code
3+
4+
on:
5+
pull_request:
6+
types: [opened, synchronize, reopened, ready_for_review]
7+
8+
permissions:
9+
contents: read
10+
11+
concurrency:
12+
group: castiron-custom-code-${{ github.event.pull_request.number }}
13+
cancel-in-progress: false
14+
15+
env:
16+
REPORTER_SHA256: 73ecd6290e9803b0d0a93af4ca4dccdbf8648cbd5c0cce51ea65fce28c7da79f
17+
18+
jobs:
19+
report:
20+
name: Castiron / baseline consistency
21+
runs-on: ubuntu-latest
22+
timeout-minutes: 10
23+
steps:
24+
- name: Record the pull request
25+
env:
26+
PR_NUMBER: ${{ github.event.pull_request.number }}
27+
REPOSITORY: ${{ github.repository }}
28+
RUN_ID: ${{ github.run_id }}
29+
RUN_ATTEMPT: ${{ github.run_attempt }}
30+
run: |
31+
mkdir -p "$RUNNER_TEMP/castiron-custom-code"
32+
jq -n --argjson pr "$PR_NUMBER" --arg repository "$REPOSITORY" \
33+
--argjson run "$RUN_ID" --argjson attempt "$RUN_ATTEMPT" \
34+
'{pr: $pr, repository: $repository, run: $run, attempt: $attempt}' \
35+
> "$RUNNER_TEMP/castiron-custom-code/context.json"
36+
37+
- name: Check out the pull request
38+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
39+
with:
40+
ref: ${{ github.event.pull_request.head.sha }}
41+
fetch-depth: 0
42+
persist-credentials: false
43+
44+
- name: Verify the reporter matches its generated workflow
45+
run: printf '%s %s\n' "$REPORTER_SHA256" scripts/castiron/custom_code_report.py | sha256sum --check --strict
46+
47+
- name: Test hash mismatch and snapshot isolation
48+
run: python3 -m unittest discover -s scripts/castiron -p test_custom_code_report.py
49+
50+
- name: Validate the codegen hash and report custom code
51+
env:
52+
GH_TOKEN: ${{ github.token }}
53+
GIT_CONFIG_COUNT: '2'
54+
GIT_CONFIG_KEY_0: credential.helper
55+
GIT_CONFIG_VALUE_0: ''
56+
GIT_CONFIG_KEY_1: credential.https://github.com.helper
57+
GIT_CONFIG_VALUE_1: '!gh auth git-credential'
58+
BASE_SHA: ${{ github.event.pull_request.base.sha }}
59+
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
60+
PUBLIC_REPOSITORY: ${{ !github.event.repository.private }}
61+
run: |
62+
git fetch --quiet --no-tags origin "$BASE_SHA" "$HEAD_SHA"
63+
mode=()
64+
if [[ "$PUBLIC_REPOSITORY" == true ]]; then mode=(--public); fi
65+
python3 -I scripts/castiron/custom_code_report.py report \
66+
--base "$BASE_SHA" --head "$HEAD_SHA" \
67+
--fetch --require-head-hash "${mode[@]}" \
68+
--out "$RUNNER_TEMP/castiron-custom-code"
69+
70+
- name: Add the report to the run summary
71+
if: always()
72+
run: |
73+
if test -f "$RUNNER_TEMP/castiron-custom-code/summary.md"; then
74+
cat "$RUNNER_TEMP/castiron-custom-code/summary.md" >> "$GITHUB_STEP_SUMMARY"
75+
fi
76+
77+
- name: Upload report and current custom-code patch
78+
if: always()
79+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
80+
with:
81+
name: castiron-custom-code-${{ github.run_id }}-${{ github.run_attempt }}
82+
path: ${{ runner.temp }}/castiron-custom-code/
83+
if-no-files-found: error
84+
retention-days: 7

api_reference/openapi.transformed.yml

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31738,6 +31738,12 @@ components:
3173831738
model:
3173931739
type: string
3174031740
description: The model to generate the completion.
31741+
obfuscation:
31742+
type: string
31743+
description: |
31744+
An obfuscation string added to normalize the size of streamed chunks as a
31745+
mitigation to certain side-channel attacks. The field is included by
31746+
default and omitted when `stream_options.include_obfuscation` is `false`.
3174131747
service_tier:
3174231748
$ref: '#/components/schemas/ServiceTier'
3174331749
system_fingerprint:
@@ -31781,13 +31787,13 @@ components:
3178131787
name: The chat completion chunk object
3178231788
group: chat
3178331789
example: |
31784-
{"id":"chatcmpl-123","object":"chat.completion.chunk","created":1694268190,"model":"gpt-4o-mini", "system_fingerprint": "fp_44709d6fcb", "choices":[{"index":0,"delta":{"role":"assistant","content":""},"logprobs":null,"finish_reason":null}]}
31790+
{"id":"chatcmpl-123","object":"chat.completion.chunk","created":1694268190,"model":"gpt-4o-mini", "system_fingerprint": "fp_44709d6fcb", "choices":[{"index":0,"delta":{"role":"assistant","content":""},"logprobs":null,"finish_reason":null}],"obfuscation":"r4N7vQ2m"}
3178531791

31786-
{"id":"chatcmpl-123","object":"chat.completion.chunk","created":1694268190,"model":"gpt-4o-mini", "system_fingerprint": "fp_44709d6fcb", "choices":[{"index":0,"delta":{"content":"Hello"},"logprobs":null,"finish_reason":null}]}
31792+
{"id":"chatcmpl-123","object":"chat.completion.chunk","created":1694268190,"model":"gpt-4o-mini", "system_fingerprint": "fp_44709d6fcb", "choices":[{"index":0,"delta":{"content":"Hello"},"logprobs":null,"finish_reason":null}],"obfuscation":"p9K3xT6w"}
3178731793

3178831794
....
3178931795

31790-
{"id":"chatcmpl-123","object":"chat.completion.chunk","created":1694268190,"model":"gpt-4o-mini", "system_fingerprint": "fp_44709d6fcb", "choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}]}
31796+
{"id":"chatcmpl-123","object":"chat.completion.chunk","created":1694268190,"model":"gpt-4o-mini", "system_fingerprint": "fp_44709d6fcb", "choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"obfuscation":""}
3179131797
CreateCompletionRequest:
3179231798
type: object
3179331799
properties:
@@ -64185,7 +64191,7 @@ components:
6418564191
x-stainless-const: true
6418664192
encrypted_content:
6418764193
type: string
64188-
maxLength: 10485760
64194+
maxLength: 20971520
6418964195
description: The encrypted content of the compaction summary.
6419064196
type: object
6419164197
required:
@@ -70602,7 +70608,7 @@ components:
7060270608
x-stainless-const: true
7060370609
encrypted_content:
7060470610
type: string
70605-
maxLength: 10485760
70611+
maxLength: 20971520
7060670612
description: The encrypted content of the compaction summary.
7060770613
type: object
7060870614
required:

scripts/castiron/README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<!-- File generated from our OpenAPI spec by Castiron. See CONTRIBUTING.md for details. -->
2+
3+
# Castiron custom-code reporting
4+
5+
Castiron maintains shared templates for these files. Prefer changing those templates
6+
for cross-SDK improvements; repository-specific customizations use the normal
7+
three-way merge and are allowed.
8+
The reporter uses Python 3.10+, Git, and `gh`; it does not import SDK code.
9+
10+
Run `python3 scripts/castiron/test_custom_code_report.py` for focused tests.
11+
The report comment includes commands to inspect the exact custom-code patch.
12+
Public reporting uses only public snapshots and needs no private repository access.
13+
14+
The workflow validates the recorded `codegen_hash`.
15+
Its hash format is documented in the reporter. Only `.github/actions/` and
16+
`.github/workflows/` are excluded from the content hash.
17+
18+
The read-only pull-request workflow runs on every branch, including drafts and
19+
forks. A separate `workflow_run` publisher reads its report as untrusted data and
20+
uses only code from the trusted default branch to update the PR comment. The
21+
publisher becomes active once its workflow is on the default branch. No branch
22+
allowlist or repository variable is needed. Never execute PR-controlled code with
23+
write credentials. Changing either workflow may require one-time AM permission.

0 commit comments

Comments
 (0)