Compare commits
6 Commits
3dfecb72c6
...
fix/gitea-
| Author | SHA1 | Date | |
|---|---|---|---|
| 328fa39c55 | |||
| bf20a84a94 | |||
| c2914af401 | |||
| 81c42c41b9 | |||
| 245c62cff3 | |||
| d91a9256c5 |
93
.github/workflows/candidate.yml
vendored
93
.github/workflows/candidate.yml
vendored
@@ -45,6 +45,9 @@ jobs:
|
||||
rails_tag_object: ${{ steps.clients.outputs.rails_tag_object }}
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: ruby/setup-ruby@003a5c4d8d6321bd302e38f6f0ec593f77f06600 # v1
|
||||
with:
|
||||
ruby-version: "3.4"
|
||||
- id: matrix
|
||||
run: echo "value=$(ruby scripts/matrix_json.rb)" >> "$GITHUB_OUTPUT"
|
||||
- id: clients
|
||||
@@ -63,8 +66,18 @@ jobs:
|
||||
- uses: ruby/setup-ruby@003a5c4d8d6321bd302e38f6f0ec593f77f06600 # v1
|
||||
with:
|
||||
ruby-version: "3.4"
|
||||
bundler-cache: true
|
||||
bundler-cache: ${{ github.server_url == 'https://github.com' }}
|
||||
working-directory: ruby-client
|
||||
- name: Install candidate dependencies without the unavailable Gitea cache service
|
||||
if: github.server_url != 'https://github.com'
|
||||
working-directory: ruby-client
|
||||
env:
|
||||
BUNDLE_APP_CONFIG: ${{ runner.temp }}/opencode-ruby-fixture-bundle-config
|
||||
BUNDLE_PATH: ${{ runner.temp }}/opencode-ruby-fixture-bundle
|
||||
run: |
|
||||
echo "BUNDLE_APP_CONFIG=$BUNDLE_APP_CONFIG" >> "$GITHUB_ENV"
|
||||
echo "BUNDLE_PATH=$BUNDLE_PATH" >> "$GITHUB_ENV"
|
||||
bundle install --jobs 4 --retry 3
|
||||
- id: client-sha
|
||||
name: Verify immutable Ruby candidate checkout
|
||||
env:
|
||||
@@ -91,7 +104,7 @@ jobs:
|
||||
mkdir -p ../.compat-evidence
|
||||
bundle exec ruby ../ruby/opencode_ruby_fixture_contract.rb
|
||||
- name: Upload fixture evidence
|
||||
if: always()
|
||||
if: always() && github.server_url == 'https://github.com'
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: ruby-fixtures-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
@@ -99,6 +112,9 @@ jobs:
|
||||
include-hidden-files: true
|
||||
if-no-files-found: warn
|
||||
retention-days: 30
|
||||
- name: State the Gitea evidence boundary
|
||||
if: always() && github.server_url != 'https://github.com'
|
||||
run: echo "Gitea executed the fixture contract, but this forge has no supported immutable artifact upload; generated JSON is transient and is not review evidence."
|
||||
|
||||
lockstep-client-contract:
|
||||
needs: prepare
|
||||
@@ -127,8 +143,18 @@ jobs:
|
||||
- uses: ruby/setup-ruby@003a5c4d8d6321bd302e38f6f0ec593f77f06600 # v1
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby }}
|
||||
bundler-cache: true
|
||||
bundler-cache: ${{ github.server_url == 'https://github.com' }}
|
||||
working-directory: opencode-rails
|
||||
- name: Install candidate dependencies without the unavailable Gitea cache service
|
||||
if: github.server_url != 'https://github.com'
|
||||
working-directory: opencode-rails
|
||||
env:
|
||||
BUNDLE_APP_CONFIG: ${{ runner.temp }}/opencode-rails-${{ matrix.ruby }}-bundle-config
|
||||
BUNDLE_PATH: ${{ runner.temp }}/opencode-rails-${{ matrix.ruby }}-bundle
|
||||
run: |
|
||||
echo "BUNDLE_APP_CONFIG=$BUNDLE_APP_CONFIG" >> "$GITHUB_ENV"
|
||||
echo "BUNDLE_PATH=$BUNDLE_PATH" >> "$GITHUB_ENV"
|
||||
bundle install --jobs 4 --retry 3
|
||||
- name: Verify immutable candidate checkouts
|
||||
env:
|
||||
EXPECTED_RUBY_SHA: ${{ needs.prepare.outputs.ruby_ref }}
|
||||
@@ -165,7 +191,7 @@ jobs:
|
||||
mkdir -p ../.compat-evidence
|
||||
bundle exec ruby ../ruby/lockstep_client_contract.rb
|
||||
- name: Upload lockstep evidence
|
||||
if: always()
|
||||
if: always() && github.server_url == 'https://github.com'
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: lockstep-ruby-${{ matrix.ruby }}-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
@@ -173,8 +199,12 @@ jobs:
|
||||
include-hidden-files: true
|
||||
if-no-files-found: warn
|
||||
retention-days: 30
|
||||
- name: State the Gitea evidence boundary
|
||||
if: always() && github.server_url != 'https://github.com'
|
||||
run: echo "Gitea executed the lockstep client contract, but this forge has no supported immutable artifact upload; generated JSON is transient and is not review evidence."
|
||||
|
||||
exact-image-contract:
|
||||
if: github.server_url == 'https://github.com'
|
||||
needs: prepare
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
@@ -227,7 +257,7 @@ jobs:
|
||||
mkdir -p .compat-evidence
|
||||
bundle exec scripts/run_image_contract.sh
|
||||
- name: Upload exact-image evidence
|
||||
if: always()
|
||||
if: always() && github.server_url == 'https://github.com'
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: image-${{ matrix.id }}-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
@@ -235,3 +265,56 @@ jobs:
|
||||
include-hidden-files: true
|
||||
if-no-files-found: warn
|
||||
retention-days: 30
|
||||
|
||||
exact-image-contract-gitea:
|
||||
if: github.server_url != 'https://github.com'
|
||||
needs: prepare
|
||||
runs-on: ubuntu-latest
|
||||
name: Gitea full exact image matrix
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
repository: ajaynomics/opencode-ruby
|
||||
ref: ${{ needs.prepare.outputs.ruby_ref }}
|
||||
path: ruby-client
|
||||
- uses: ruby/setup-ruby@003a5c4d8d6321bd302e38f6f0ec593f77f06600 # v1
|
||||
with:
|
||||
ruby-version: "3.4"
|
||||
- name: Install candidate dependencies outside the checkout
|
||||
working-directory: ruby-client
|
||||
env:
|
||||
BUNDLE_APP_CONFIG: ${{ runner.temp }}/opencode-ruby-bundle-config
|
||||
BUNDLE_PATH: ${{ runner.temp }}/opencode-ruby-bundle
|
||||
run: |
|
||||
echo "BUNDLE_APP_CONFIG=$BUNDLE_APP_CONFIG" >> "$GITHUB_ENV"
|
||||
echo "BUNDLE_PATH=$BUNDLE_PATH" >> "$GITHUB_ENV"
|
||||
bundle install --jobs 4 --retry 3
|
||||
- id: client-sha
|
||||
name: Verify immutable Ruby candidate checkout
|
||||
env:
|
||||
EXPECTED_CLIENT_SHA: ${{ needs.prepare.outputs.ruby_ref }}
|
||||
run: |
|
||||
actual_client_sha="$(git -C ruby-client rev-parse HEAD)"
|
||||
test "$actual_client_sha" = "$EXPECTED_CLIENT_SHA"
|
||||
echo "value=$actual_client_sha" >> "$GITHUB_OUTPUT"
|
||||
- name: Resolve the private Docker host transport
|
||||
run: |
|
||||
probe_host="$(ruby scripts/private_default_gateway.rb)"
|
||||
echo "OPENCODE_PROBE_HOST=$probe_host" >> "$GITHUB_ENV"
|
||||
- name: Exercise the complete manifest matrix without artifact claims
|
||||
env:
|
||||
BUNDLE_GEMFILE: ${{ github.workspace }}/ruby-client/Gemfile
|
||||
OPENCODE_RUBY_PATH: ${{ github.workspace }}/ruby-client
|
||||
OPENCODE_RUBY_COMMIT: ${{ steps.client-sha.outputs.value }}
|
||||
OPENCODE_RAILS_COMMIT: ${{ needs.prepare.outputs.rails_ref }}
|
||||
OPENCODE_COMPAT_EVIDENCE_DIR: ${{ github.workspace }}/.compat-evidence
|
||||
OPENCODE_COMPAT_RUN_ID: ${{ github.run_id }}
|
||||
OPENCODE_COMPAT_RUN_ATTEMPT: ${{ github.run_attempt }}
|
||||
OPENCODE_COMPAT_HEAD_SHA: ${{ github.sha }}
|
||||
OPENCODE_COMPAT_REPOSITORY: ${{ github.repository }}
|
||||
OPENCODE_COMPAT_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
run: scripts/run_image_matrix_contract.sh
|
||||
- name: State the Gitea evidence boundary
|
||||
if: always()
|
||||
run: echo "Gitea's exact-image path uploads nothing; generated JSON is transient and is not review evidence. This job passes only after every manifest image passes."
|
||||
|
||||
15
README.md
15
README.md
@@ -82,11 +82,16 @@ expected text byte-for-byte and the deterministic model stub to observe exactly
|
||||
one request and exactly one authoritative assistant message. It never calls an
|
||||
external model provider.
|
||||
|
||||
Candidate CI uploads machine-readable fixture, lockstep-client, and exact-image
|
||||
evidence for 30 days. These artifacts are review inputs, not certification by
|
||||
themselves. A person must review a passing artifact and commit the durable
|
||||
certification document under `evidence/`; no workflow commits or promotes its
|
||||
own result.
|
||||
On GitHub, candidate CI uploads machine-readable fixture, lockstep-client, and
|
||||
exact-image evidence for 30 days. These artifacts are review inputs, not
|
||||
certification by themselves. Gitea runs the same repository, fixture, and
|
||||
lockstep contracts and executes every exact-image manifest entry sequentially,
|
||||
because its runner cannot expand a matrix from a dependency job's JSON output.
|
||||
The installed Gitea artifact service does not support the pinned GitHub upload
|
||||
action, so Gitea deliberately uploads nothing: its generated JSON is transient
|
||||
and must not be described as review evidence. A person must review a passing
|
||||
GitHub artifact and commit the durable certification document under `evidence/`;
|
||||
no workflow commits or promotes its own result.
|
||||
|
||||
`manifests/image-matrix.json` binds the active pending matrix to both candidate
|
||||
commits. Its `previous_certification` entries preserve the last alpha7 result;
|
||||
|
||||
@@ -126,12 +126,16 @@ still does not certify a consumer's ActiveRecord schema, persistence callbacks,
|
||||
container adapter, or application canary; those remain consumer-owned profile
|
||||
evidence.
|
||||
|
||||
CI writes canonical JSON artifacts for the shared fixture, lockstep client, and
|
||||
each exact-image target. Artifact retention is 30 days and supplies reviewable
|
||||
workflow provenance; it is not the long-term ledger. After review, copy the
|
||||
relevant facts into a repository evidence document bound to the complete tuple
|
||||
fingerprint. Automated workflows never update certified evidence or promote a
|
||||
tuple.
|
||||
GitHub CI writes canonical JSON artifacts for the shared fixture, lockstep
|
||||
client, and each exact-image target. Artifact retention is 30 days and supplies
|
||||
reviewable workflow provenance; it is not the long-term ledger. Gitea executes
|
||||
the same contracts, with its exact-image targets run sequentially from the full
|
||||
generated manifest, but its installed artifact service cannot accept the
|
||||
reviewed GitHub upload action. Gitea therefore keeps generated JSON transient
|
||||
and makes no artifact-evidence claim. After reviewing a GitHub artifact, copy
|
||||
the relevant facts into a repository evidence document bound to the complete
|
||||
tuple fingerprint. Automated workflows never update certified evidence or
|
||||
promote a tuple.
|
||||
|
||||
The command clears `candidate` after promotion. It sets the repository-wide
|
||||
`migration_state` to `certified` only after every consumer has certified
|
||||
|
||||
28
scripts/private_default_gateway.rb
Executable file
28
scripts/private_default_gateway.rb
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "ipaddr"
|
||||
|
||||
route_path = ARGV.fetch(0, "/proc/net/route")
|
||||
routes = File.foreach(route_path).drop(1).filter_map do |line|
|
||||
fields = line.split
|
||||
next unless fields.length >= 8
|
||||
next unless fields.fetch(1) == "00000000"
|
||||
next unless (fields.fetch(3).to_i(16) & 0x2) == 0x2
|
||||
|
||||
fields
|
||||
end
|
||||
|
||||
routes.sort_by { |fields| fields.fetch(6).to_i }.each do |fields|
|
||||
gateway_hex = fields.fetch(2)
|
||||
next unless gateway_hex.match?(/\A[0-9A-Fa-f]{8}\z/)
|
||||
|
||||
gateway = gateway_hex.scan(/../).reverse.map { |octet| octet.to_i(16) }.join(".")
|
||||
address = IPAddr.new(gateway)
|
||||
next unless address.ipv4? && address.private?
|
||||
|
||||
puts address
|
||||
exit 0
|
||||
end
|
||||
|
||||
abort "no private IPv4 default-route gateway found in #{route_path}"
|
||||
@@ -6,6 +6,7 @@ image="${OPENCODE_IMAGE:-}"
|
||||
gem_path="${OPENCODE_RUBY_PATH:-}"
|
||||
expected_gem_commit="${OPENCODE_RUBY_COMMIT:-}"
|
||||
evidence_path="${OPENCODE_COMPAT_EVIDENCE_PATH:-}"
|
||||
probe_host="${OPENCODE_PROBE_HOST:-127.0.0.1}"
|
||||
container_name="opencode-compat-${RANDOM}-$$"
|
||||
llm_container_name="opencode-compat-llm-${RANDOM}-$$"
|
||||
network_name="opencode-compat-net-${RANDOM}-$$"
|
||||
@@ -97,6 +98,18 @@ if [[ ! "$image" =~ ^[^[:space:]@]+@sha256:[0-9a-f]{64}$ ]]; then
|
||||
exit 2
|
||||
fi
|
||||
fi
|
||||
if ! ruby -ripaddr -e '
|
||||
begin
|
||||
address = IPAddr.new(ARGV.fetch(0))
|
||||
valid = address.ipv4? && (address.loopback? || address.private?)
|
||||
rescue IPAddr::InvalidAddressError
|
||||
valid = false
|
||||
end
|
||||
exit(valid ? 0 : 1)
|
||||
' "$probe_host"; then
|
||||
echo "OPENCODE_PROBE_HOST must be a loopback or private IPv4 address" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [[ ! "$expected_gem_commit" =~ ^[0-9a-f]{40}$ ]]; then
|
||||
echo "OPENCODE_RUBY_COMMIT must be a full lowercase 40-character Git commit" >&2
|
||||
@@ -121,11 +134,14 @@ docker run --detach \
|
||||
--name "$llm_container_name" \
|
||||
--network "$network_name" \
|
||||
--network-alias compat-llm \
|
||||
--volume "$repo_root/scripts:/compat:ro" \
|
||||
"$python_image" \
|
||||
python /compat/fake_llm.py --port 8080 --port-file /tmp/compat-port \
|
||||
python -c 'import time; time.sleep(3600)' \
|
||||
>/dev/null
|
||||
llm_container_started=1
|
||||
docker cp "$repo_root/scripts/fake_llm.py" "$llm_container_name:/tmp/fake_llm.py"
|
||||
docker exec --detach \
|
||||
"$llm_container_name" \
|
||||
python /tmp/fake_llm.py --port 8080 --port-file /tmp/compat-port
|
||||
|
||||
for _ in $(seq 1 100); do
|
||||
if docker exec "$llm_container_name" wget -qO- http://127.0.0.1:8080/health >/dev/null 2>&1; then
|
||||
@@ -168,7 +184,7 @@ config_json="$(jq -cn --arg url "http://compat-llm:8080/v1" '{
|
||||
docker run --detach \
|
||||
--name "$container_name" \
|
||||
--network "$network_name" \
|
||||
--publish 127.0.0.1::4096 \
|
||||
--publish "${probe_host}::4096" \
|
||||
--env "OPENCODE_CONFIG_CONTENT=$config_json" \
|
||||
--env OPENCODE_DISABLE_AUTOUPDATE=1 \
|
||||
--env OPENCODE_DISABLE_AUTOCOMPACT=1 \
|
||||
@@ -180,7 +196,7 @@ docker run --detach \
|
||||
opencode_container_started=1
|
||||
|
||||
host_port="$(docker port "$container_name" 4096/tcp | sed -E 's/.*:([0-9]+)$/\1/' | head -1)"
|
||||
base_url="http://127.0.0.1:${host_port}"
|
||||
base_url="http://${probe_host}:${host_port}"
|
||||
|
||||
ready=0
|
||||
for _ in $(seq 1 120); do
|
||||
|
||||
44
scripts/run_image_matrix_contract.sh
Executable file
44
scripts/run_image_matrix_contract.sh
Executable file
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
evidence_dir="${OPENCODE_COMPAT_EVIDENCE_DIR:-$repo_root/.compat-evidence}"
|
||||
matrix_json="$(ruby "$repo_root/scripts/matrix_json.rb")"
|
||||
entry_count="$(jq -er '.include | length' <<<"$matrix_json")"
|
||||
|
||||
if [[ ! "$entry_count" =~ ^[1-9][0-9]*$ ]]; then
|
||||
echo "exact image matrix must contain at least one entry" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
mkdir -p "$evidence_dir"
|
||||
|
||||
for ((index = 0; index < entry_count; index++)); do
|
||||
entry="$(jq -ec --argjson index "$index" '.include[$index]' <<<"$matrix_json")"
|
||||
matrix_id="$(jq -er '.id' <<<"$entry")"
|
||||
image="$(jq -er '.image' <<<"$entry")"
|
||||
expected_version="$(jq -er '.version' <<<"$entry")"
|
||||
required_profiles="$(jq -ec '.required_consumer_profiles' <<<"$entry")"
|
||||
evidence_path="$evidence_dir/$matrix_id.json"
|
||||
|
||||
printf 'Running exact image matrix entry %s (%s)\n' "$matrix_id" "$image"
|
||||
OPENCODE_IMAGE="$image" \
|
||||
OPENCODE_EXPECTED_VERSION="$expected_version" \
|
||||
OPENCODE_MATRIX_ID="$matrix_id" \
|
||||
OPENCODE_REQUIRED_CONSUMER_PROFILES="$required_profiles" \
|
||||
OPENCODE_COMPAT_EVIDENCE_PATH="$evidence_path" \
|
||||
bundle exec "$repo_root/scripts/run_image_contract.sh"
|
||||
|
||||
jq -e \
|
||||
--arg matrix_id "$matrix_id" \
|
||||
--arg image "$image" \
|
||||
--arg version "$expected_version" \
|
||||
'.status == "pass" and
|
||||
.matrix_target == $matrix_id and
|
||||
.image.requested == $image and
|
||||
.image.reported_version == $version' \
|
||||
"$evidence_path" >/dev/null
|
||||
printf 'Exact image matrix entry %s passed; JSON remains transient on this forge.\n' "$matrix_id"
|
||||
done
|
||||
|
||||
printf 'Full exact image matrix passed (%s entries).\n' "$entry_count"
|
||||
@@ -4,11 +4,13 @@ require "fileutils"
|
||||
require "json"
|
||||
require "minitest/autorun"
|
||||
require "open3"
|
||||
require "rbconfig"
|
||||
require "tmpdir"
|
||||
|
||||
class ImageContractEvidenceTest < Minitest::Test
|
||||
ROOT = File.expand_path("..", __dir__)
|
||||
RUNNER = File.join(ROOT, "scripts/run_image_contract.sh")
|
||||
GATEWAY_RESOLVER = File.join(ROOT, "scripts/private_default_gateway.rb")
|
||||
VALID_IMAGE = "ghcr.io/anomalyco/opencode@sha256:#{'a' * 64}"
|
||||
|
||||
def setup
|
||||
@@ -108,6 +110,49 @@ class ImageContractEvidenceTest < Minitest::Test
|
||||
assert_failed_without_docker(evidence_path)
|
||||
end
|
||||
|
||||
def test_rejects_malformed_ipv6_and_public_probe_hosts_before_docker
|
||||
checkout, commit = git_checkout
|
||||
|
||||
["not-an-address", "::1", "8.8.8.8"].each_with_index do |probe_host, index|
|
||||
evidence_path = File.join(@tmp, "probe-host-#{index}.json")
|
||||
environment = base_environment(checkout, commit, evidence_path).merge(
|
||||
"OPENCODE_PROBE_HOST" => probe_host
|
||||
)
|
||||
|
||||
_output, error, status = run_contract(environment)
|
||||
|
||||
assert_equal 2, status.exitstatus
|
||||
assert_match(/loopback or private IPv4 address/, error)
|
||||
assert_failed_without_docker(evidence_path)
|
||||
end
|
||||
end
|
||||
|
||||
def test_resolves_a_private_default_gateway_from_linux_route_hex
|
||||
route_path = File.join(@tmp, "route")
|
||||
File.write(route_path, <<~ROUTES)
|
||||
Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
|
||||
eth0 00000000 010011AC 0003 0 0 10 00000000 0 0 0
|
||||
ROUTES
|
||||
|
||||
output, error, status = Open3.capture3(RbConfig.ruby, GATEWAY_RESOLVER, route_path)
|
||||
|
||||
assert status.success?, error
|
||||
assert_equal "172.17.0.1\n", output
|
||||
end
|
||||
|
||||
def test_gateway_resolver_rejects_a_public_default_gateway
|
||||
route_path = File.join(@tmp, "public-route")
|
||||
File.write(route_path, <<~ROUTES)
|
||||
Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
|
||||
eth0 00000000 08080808 0003 0 0 10 00000000 0 0 0
|
||||
ROUTES
|
||||
|
||||
_output, error, status = Open3.capture3(RbConfig.ruby, GATEWAY_RESOLVER, route_path)
|
||||
|
||||
refute status.success?
|
||||
assert_match(/no private IPv4 default-route gateway found/, error)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def base_environment(checkout, commit, evidence_path)
|
||||
|
||||
@@ -275,6 +275,38 @@ class RepositoryTest < Minitest::Test
|
||||
refute_match(/\b(kamal|kubectl|helm|nomad|docker\s+service|gh\s+pr\s+merge)\b/i, workflow)
|
||||
end
|
||||
|
||||
def test_candidate_workflow_has_an_explicit_dual_forge_evidence_boundary
|
||||
workflow = File.read(File.join(ROOT, ".github/workflows/candidate.yml"))
|
||||
upload_conditions = workflow.scan(
|
||||
/- name: Upload (?:fixture|lockstep|exact-image) evidence\n\s+if: ([^\n]+)\n\s+uses: actions\/upload-artifact@/
|
||||
).flatten
|
||||
|
||||
assert_equal 3, upload_conditions.length
|
||||
assert_equal ["always() && github.server_url == 'https://github.com'"], upload_conditions.uniq
|
||||
assert_includes workflow, "bundler-cache: ${{ github.server_url == 'https://github.com' }}"
|
||||
assert_includes workflow, "exact-image-contract-gitea:"
|
||||
assert_includes workflow, "if: github.server_url != 'https://github.com'"
|
||||
assert_includes workflow, "run: scripts/run_image_matrix_contract.sh"
|
||||
assert_includes workflow, 'probe_host="$(ruby scripts/private_default_gateway.rb)"'
|
||||
assert_includes workflow, 'echo "OPENCODE_PROBE_HOST=$probe_host" >> "$GITHUB_ENV"'
|
||||
assert_operator workflow.scan('BUNDLE_GEMFILE: ${{ github.workspace }}/ruby-client/Gemfile').length, :>=, 2
|
||||
assert_operator workflow.scan("generated JSON is transient and is not review evidence").length, :>=, 3
|
||||
|
||||
gitea_job = workflow.split(/^ exact-image-contract-gitea:\n/, 2).fetch(1)
|
||||
refute_includes gitea_job, "actions/upload-artifact@"
|
||||
end
|
||||
|
||||
def test_gitea_matrix_runner_uses_every_generated_entry_without_hardcoded_coordinates
|
||||
runner = File.read(File.join(ROOT, "scripts/run_image_matrix_contract.sh"))
|
||||
|
||||
assert_includes runner, 'matrix_json="$(ruby "$repo_root/scripts/matrix_json.rb")"'
|
||||
assert_includes runner, 'for ((index = 0; index < entry_count; index++))'
|
||||
assert_includes runner, 'bundle exec "$repo_root/scripts/run_image_contract.sh"'
|
||||
assert_includes runner, '.image.reported_version == $version'
|
||||
refute_match(/upstream-[0-9]/, runner)
|
||||
refute_match(/ghcr\.io\/anomalyco/, runner)
|
||||
end
|
||||
|
||||
def test_tuple_promotion_has_no_command_execution_or_deployment_client
|
||||
paths = %w[
|
||||
lib/opencode_compat/runtime_tuple_promoter.rb
|
||||
@@ -295,6 +327,11 @@ class RepositoryTest < Minitest::Test
|
||||
assert_includes probe, "ExactLiveContract.assert_authoritative_assistant_count!"
|
||||
refute_includes probe, "full_text.include?"
|
||||
assert_includes runner, "exact_live_contract.rb"
|
||||
assert_includes runner, 'docker cp "$repo_root/scripts/fake_llm.py"'
|
||||
refute_includes runner, '--volume "$repo_root/scripts:/compat:ro"'
|
||||
assert_includes runner, '--publish "${probe_host}::4096"'
|
||||
assert_includes runner, 'base_url="http://${probe_host}:${host_port}"'
|
||||
refute_includes runner, "--publish 0.0.0.0"
|
||||
assert_includes runner, "OPENCODE_COMPAT_EVIDENCE_PATH"
|
||||
assert_includes runner, "OPENCODE_EXPECTED_VERSION"
|
||||
refute_match(/request_count.*-lt\s+1/, runner)
|
||||
|
||||
Reference in New Issue
Block a user