Skip to content
Merged
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
13 changes: 9 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ jobs:
shopt -s nullglob
for asset in release/dist/*; do
case "${asset}" in
*.tar.gz|*.zip|*.json|*/SHA256SUMS|*SHA256SUMS)
*.tar.gz|*.zip|*.json|*.sh|*.ps1|*/SHA256SUMS|*SHA256SUMS)
cosign sign-blob --yes \
--output-signature "${asset}.sig" \
--output-certificate "${asset}.pem" \
Expand All @@ -196,6 +196,8 @@ jobs:
release/dist/*.tar.gz
release/dist/*.zip
release/dist/*.json
release/dist/*.sh
release/dist/*.ps1
release/dist/SHA256SUMS

- name: Write release notes preamble
Expand All @@ -205,18 +207,19 @@ jobs:
{
printf '%s\n' '## Install and verify'
printf '\n'
printf '%s\n' "- Latest-release install and full verification commands: https://github.com/runecode-ai/runecode/blob/${RELEASE_TAG}/docs/install-verify.md"
printf '%s\n' "- Maintainer release procedure and required repository settings: https://github.com/runecode-ai/runecode/blob/${RELEASE_TAG}/docs/release-process.md"
printf '%s\n' "- Latest-release install and full verification commands: https://github.com/runecode-systems/runecode/blob/${RELEASE_TAG}/docs/install-verify.md"
printf '%s\n' "- Maintainer release procedure and required repository settings: https://github.com/runecode-systems/runecode/blob/${RELEASE_TAG}/docs/release-process.md"
printf '\n'
printf '%s\n' '## Included assets'
printf '\n'
printf '%s\n' '- Unsigned archives built from the canonical flake package `nix build .#release-artifacts`'
printf '%s\n' '- First-party installer scripts: `install-runecode.sh` and `install-runecode.ps1`'
printf '%s\n' "- Canonical unsigned release manifest: \`runecode_${RELEASE_TAG}_release-manifest.json\`"
printf '%s\n' "- Per-platform archives for Linux, macOS, and Windows under the pattern \`runecode_${RELEASE_TAG}_{os}_{arch}\`"
printf '%s\n' "- Release-level SBOM: \`runecode_${RELEASE_TAG}_sbom.spdx.json\`"
printf '%s\n' '- Checksums: `SHA256SUMS`'
printf '%s\n' '- Keyless cosign signatures and certificates for every primary asset (`.sig` and `.pem`)'
printf '%s\n' '- GitHub build provenance attestations for each archive, the release manifest, the SBOM, and `SHA256SUMS`'
printf '%s\n' '- GitHub artifact attestations for each archive, both installer scripts, the release manifest, the SBOM, and `SHA256SUMS`'
} > release-notes.md

- name: Publish GitHub release
Expand All @@ -238,6 +241,8 @@ jobs:
"SHA256SUMS"
"runecode_${RELEASE_TAG}_release-manifest.json"
"runecode_${RELEASE_TAG}_sbom.spdx.json"
"install-runecode.sh"
"install-runecode.ps1"
)

mapfile -t archive_assets < <(jq -er '.archives[].file' "${manifest}")
Expand Down
84 changes: 17 additions & 67 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# RuneCode — Security-first AI coding: isolated execution, signed, auditable

[![CI](https://github.com/runecode-ai/runecode/actions/workflows/ci.yml/badge.svg)](https://github.com/runecode-ai/runecode/actions/workflows/ci.yml)
[![CI](https://github.com/runecode-systems/runecode/actions/workflows/ci.yml/badge.svg)](https://github.com/runecode-systems/runecode/actions/workflows/ci.yml)
[![Status: alpha.11 in progress](https://img.shields.io/badge/status-alpha.11%20in%20progress-orange)](runecontext/project/roadmap.md)
[![License: Apache-2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)

Expand Down Expand Up @@ -66,79 +66,29 @@ The official release channel is GitHub Releases.
- Canonical unsigned release artifacts come from `nix build --no-link .#release-artifacts`
- Published release assets are signed and attested in GitHub Actions
- Supported targets: Linux (`amd64`, `arm64`), macOS (`amd64`, `arm64`), Windows (`amd64`, `arm64`)
- Requires `gh` and `cosign`
- Primary install path: first-party installer scripts from signed release assets

Quick verified install for Linux and macOS:
### Primary path: signed installer script (Linux/macOS)

This path downloads the installer from the signed release asset set. The installer bootstraps verification tooling if needed, verifies its own signed metadata plus the selected archive, prints the verification details, and prompts before installing.

```bash
set -euo pipefail

REPO="runecode-ai/runecode"
# Newest published release, including prereleases during pre-alpha.
# Ordered by creation date; assumes no out-of-order backport releases.
VERSION="$(gh release list --repo "$REPO" --exclude-drafts --limit 1 --json tagName --jq '.[0].tagName')"

if [ -z "$VERSION" ]; then
printf 'no published release found for %s\n' "$REPO" >&2
exit 1
fi

OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
ARCH="$(uname -m)"

case "$ARCH" in
x86_64) ARCH="amd64" ;;
arm64|aarch64) ARCH="arm64" ;;
*) printf 'unsupported architecture: %s\n' "$ARCH" >&2; exit 1 ;;
esac

case "$OS" in
linux|darwin) ;;
*) printf 'unsupported operating system: %s\n' "$OS" >&2; exit 1 ;;
esac

ARCHIVE="runecode_${VERSION}_${OS}_${ARCH}.tar.gz"
WORKDIR="$(mktemp -d)"
trap 'rm -rf "$WORKDIR"' EXIT

cd "$WORKDIR"

gh release download "$VERSION" --repo "$REPO" \
--pattern "$ARCHIVE" \
--pattern "$ARCHIVE.sig" \
--pattern "$ARCHIVE.pem" \
--pattern "SHA256SUMS" \
--pattern "SHA256SUMS.sig" \
--pattern "SHA256SUMS.pem"

cosign verify-blob \
--certificate-identity "https://github.com/${REPO}/.github/workflows/release.yml@refs/tags/${VERSION}" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
--signature "SHA256SUMS.sig" \
--certificate "SHA256SUMS.pem" \
"SHA256SUMS"

cosign verify-blob \
--certificate-identity "https://github.com/${REPO}/.github/workflows/release.yml@refs/tags/${VERSION}" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
--signature "${ARCHIVE}.sig" \
--certificate "${ARCHIVE}.pem" \
"$ARCHIVE"

if command -v sha256sum >/dev/null 2>&1; then
grep -F " ${ARCHIVE}" SHA256SUMS | sha256sum -c -
else
grep -F " ${ARCHIVE}" SHA256SUMS | shasum -a 256 -c -
fi

mkdir unpack
tar -xzf "$ARCHIVE" -C unpack

install -d "$HOME/.local/bin"
install -m 0755 "unpack/runecode_${VERSION}_${OS}_${ARCH}"/bin/runecode* "$HOME/.local/bin/"
TAG="v0.1.0-alpha.11"
curl -fsSLO "https://github.com/runecode-systems/runecode/releases/download/${TAG}/install-runecode.sh"
bash install-runecode.sh --version "$TAG"
```

This quick path verifies signed checksums and the signed archive before install. For Windows steps and full provenance verification with `gh attestation verify`, see `docs/install-verify.md`.
If you want the installer to resolve the newest published release automatically, pass `--latest` instead of `--version <tag>`.

This bootstrap path still trusts the initial script download enough to start it. Once running, the installer verifies the signed checksum manifest, verifies the running installer against the signed release metadata and attestation, verifies the selected archive, prints the relevant hashes and signature details, and then requires explicit approval before installing.

Windows uses the signed `install-runecode.ps1` release asset. On Windows `arm64`, preinstall `cosign v2.4.1` before running the installer because the temporary helper bootstrap for that pinned version is only available for Windows `amd64`.

Windows and full manual verification options are documented in `docs/install-verify.md`.

For explicit manual verification before executing any installer code, including `gh` + `cosign` and `curl` + `cosign` flows, see `docs/install-verify.md`.

## Implemented in this repo today:
- A protocol/schema bundle in `protocol/schemas/` with an authoritative manifest at `protocol/schemas/manifest.json`
Expand Down
6 changes: 3 additions & 3 deletions cmd/runecode-auditd/configure_verification_inputs.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import (
"fmt"
"io"

"github.com/runecode-ai/runecode/internal/auditd"
"github.com/runecode-ai/runecode/internal/trustpolicy"
"github.com/runecode-ai/runecode/third_party/jsoncanonicalizer"
"github.com/runecode-systems/runecode/internal/auditd"
"github.com/runecode-systems/runecode/internal/trustpolicy"
"github.com/runecode-systems/runecode/third_party/jsoncanonicalizer"
)

func handleConfigureVerificationInputs(args []string, stdout io.Writer) error {
Expand Down
4 changes: 2 additions & 2 deletions cmd/runecode-auditd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import (
"io"
"os"

"github.com/runecode-ai/runecode/internal/auditd"
"github.com/runecode-ai/runecode/internal/trustpolicy"
"github.com/runecode-systems/runecode/internal/auditd"
"github.com/runecode-systems/runecode/internal/trustpolicy"
)

type usageError struct{ message string }
Expand Down
4 changes: 2 additions & 2 deletions cmd/runecode-auditd/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import (
"strings"
"testing"

"github.com/runecode-ai/runecode/internal/trustpolicy"
"github.com/runecode-ai/runecode/third_party/jsoncanonicalizer"
"github.com/runecode-systems/runecode/internal/trustpolicy"
"github.com/runecode-systems/runecode/third_party/jsoncanonicalizer"
)

func TestValidateSignerEvidenceCLI(t *testing.T) {
Expand Down
10 changes: 5 additions & 5 deletions cmd/runecode-broker/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ import (
"strings"
"time"

"github.com/runecode-ai/runecode/internal/artifacts"
"github.com/runecode-ai/runecode/internal/brokerapi"
"github.com/runecode-ai/runecode/internal/policyengine"
"github.com/runecode-ai/runecode/internal/trustpolicy"
"github.com/runecode-ai/runecode/third_party/jsoncanonicalizer"
"github.com/runecode-systems/runecode/internal/artifacts"
"github.com/runecode-systems/runecode/internal/brokerapi"
"github.com/runecode-systems/runecode/internal/policyengine"
"github.com/runecode-systems/runecode/internal/trustpolicy"
"github.com/runecode-systems/runecode/third_party/jsoncanonicalizer"
)

func defaultBrokerStoreRoot() string {
Expand Down
2 changes: 1 addition & 1 deletion cmd/runecode-broker/local_api_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"fmt"
"sync"

"github.com/runecode-ai/runecode/internal/brokerapi"
"github.com/runecode-systems/runecode/internal/brokerapi"
)

type brokerLocalAPI interface {
Expand Down
2 changes: 1 addition & 1 deletion cmd/runecode-broker/local_api_client_extended.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package main
import (
"context"

"github.com/runecode-ai/runecode/internal/brokerapi"
"github.com/runecode-systems/runecode/internal/brokerapi"
)

func (c *localAPIClient) AuditVerificationGet(ctx context.Context, req brokerapi.AuditVerificationGetRequest) (brokerapi.AuditVerificationGetResponse, *brokerapi.ErrorResponse) {
Expand Down
4 changes: 2 additions & 2 deletions cmd/runecode-broker/local_api_live_ipc_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import (
"context"
"fmt"

"github.com/runecode-ai/runecode/internal/brokerapi"
"github.com/runecode-ai/runecode/internal/localbootstrap"
"github.com/runecode-systems/runecode/internal/brokerapi"
"github.com/runecode-systems/runecode/internal/localbootstrap"
)

type liveIPCClientDeps struct {
Expand Down
4 changes: 2 additions & 2 deletions cmd/runecode-broker/local_api_live_ipc_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import (
"path/filepath"
"testing"

"github.com/runecode-ai/runecode/internal/brokerapi"
"github.com/runecode-ai/runecode/internal/localbootstrap"
"github.com/runecode-systems/runecode/internal/brokerapi"
"github.com/runecode-systems/runecode/internal/localbootstrap"
)

func TestNewLiveIPCLocalAPIClientUsesResolvedRepoScopeForDial(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion cmd/runecode-broker/local_ipc_config_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package main
import (
"sync"

"github.com/runecode-ai/runecode/internal/brokerapi"
"github.com/runecode-systems/runecode/internal/brokerapi"
)

var (
Expand Down
4 changes: 2 additions & 2 deletions cmd/runecode-broker/main_artifact_cmds.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import (
"io"
"os"

"github.com/runecode-ai/runecode/internal/artifacts"
"github.com/runecode-ai/runecode/internal/brokerapi"
"github.com/runecode-systems/runecode/internal/artifacts"
"github.com/runecode-systems/runecode/internal/brokerapi"
)

func handleListArtifacts(_ []string, service *brokerapi.Service, stdout io.Writer) error {
Expand Down
6 changes: 3 additions & 3 deletions cmd/runecode-broker/main_base.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import (
"os"
"strings"

"github.com/runecode-ai/runecode/internal/auditd"
"github.com/runecode-ai/runecode/internal/brokerapi"
"github.com/runecode-ai/runecode/internal/localbootstrap"
"github.com/runecode-systems/runecode/internal/auditd"
"github.com/runecode-systems/runecode/internal/brokerapi"
"github.com/runecode-systems/runecode/internal/localbootstrap"
)

type usageError struct{ message string }
Expand Down
4 changes: 2 additions & 2 deletions cmd/runecode-broker/main_base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (
"strings"
"testing"

"github.com/runecode-ai/runecode/internal/brokerapi"
"github.com/runecode-ai/runecode/internal/localbootstrap"
"github.com/runecode-systems/runecode/internal/brokerapi"
"github.com/runecode-systems/runecode/internal/localbootstrap"
)

func TestResolveExplicitLiveIPCTargetConfigUsesDefaultConfigSeam(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions cmd/runecode-broker/main_cli_approval_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import (
"strings"
"testing"

"github.com/runecode-ai/runecode/internal/brokerapi"
"github.com/runecode-ai/runecode/internal/trustpolicy"
"github.com/runecode-systems/runecode/internal/brokerapi"
"github.com/runecode-systems/runecode/internal/trustpolicy"
)

func TestAuditReadinessAndVerificationCommands(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions cmd/runecode-broker/main_cli_artifact_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import (
"testing"
"time"

"github.com/runecode-ai/runecode/internal/artifacts"
"github.com/runecode-ai/runecode/internal/brokerapi"
"github.com/runecode-systems/runecode/internal/artifacts"
"github.com/runecode-systems/runecode/internal/brokerapi"
)

func TestPutListHeadGetArtifactCLI(t *testing.T) {
Expand Down
6 changes: 3 additions & 3 deletions cmd/runecode-broker/main_cli_core_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import (
"testing"
"time"

"github.com/runecode-ai/runecode/internal/artifacts"
"github.com/runecode-ai/runecode/internal/brokerapi"
"github.com/runecode-ai/runecode/internal/launcherbackend"
"github.com/runecode-systems/runecode/internal/artifacts"
"github.com/runecode-systems/runecode/internal/brokerapi"
"github.com/runecode-systems/runecode/internal/launcherbackend"
)

func TestHelpAndUnknownCommand(t *testing.T) {
Expand Down
12 changes: 6 additions & 6 deletions cmd/runecode-broker/main_cli_helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ import (
"testing"
"time"

"github.com/runecode-ai/runecode/internal/artifacts"
"github.com/runecode-ai/runecode/internal/brokerapi"
"github.com/runecode-ai/runecode/internal/policyengine"
"github.com/runecode-ai/runecode/internal/secretsd"
"github.com/runecode-ai/runecode/internal/trustpolicy"
"github.com/runecode-ai/runecode/third_party/jsoncanonicalizer"
"github.com/runecode-systems/runecode/internal/artifacts"
"github.com/runecode-systems/runecode/internal/brokerapi"
"github.com/runecode-systems/runecode/internal/policyengine"
"github.com/runecode-systems/runecode/internal/secretsd"
"github.com/runecode-systems/runecode/internal/trustpolicy"
"github.com/runecode-systems/runecode/third_party/jsoncanonicalizer"
)

func mustJSONRawMessage(t *testing.T, value any) json.RawMessage {
Expand Down
4 changes: 2 additions & 2 deletions cmd/runecode-broker/main_cli_ledger_seed_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import (
"strings"
"time"

"github.com/runecode-ai/runecode/internal/trustpolicy"
"github.com/runecode-ai/runecode/third_party/jsoncanonicalizer"
"github.com/runecode-systems/runecode/internal/trustpolicy"
"github.com/runecode-systems/runecode/third_party/jsoncanonicalizer"
)

func seedLedgerForBrokerCommandTest(root string) error {
Expand Down
10 changes: 5 additions & 5 deletions cmd/runecode-broker/main_cli_local_api_adoption_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import (
"strings"
"testing"

"github.com/runecode-ai/runecode/internal/artifacts"
"github.com/runecode-ai/runecode/internal/brokerapi"
"github.com/runecode-ai/runecode/internal/secretsd"
"github.com/runecode-ai/runecode/internal/trustpolicy"
"github.com/runecode-systems/runecode/internal/artifacts"
"github.com/runecode-systems/runecode/internal/brokerapi"
"github.com/runecode-systems/runecode/internal/secretsd"
"github.com/runecode-systems/runecode/internal/trustpolicy"
)

func TestCLIAdoptionRoutesRunApprovalVersionAndLogThroughLocalRPC(t *testing.T) {
Expand Down Expand Up @@ -412,7 +412,7 @@ func writeGitRemoteMutationRequestFiles(t *testing.T) (string, string, string, s
"schema_version": "0.1.0",
"request_kind": "git_ref_update",
"target_ref": "refs/heads/main",
"repository_identity": map[string]any{"canonical_host": "github.com", "canonical_path_prefix": "runecode-ai/runecode", "git_repository_identity": "github.com/runecode-ai/runecode"},
"repository_identity": map[string]any{"canonical_host": "github.com", "canonical_path_prefix": "runecode-systems/runecode", "git_repository_identity": "github.com/runecode-systems/runecode"},
"expected_old_ref_hash": map[string]any{"hash_alg": "sha256", "hash": strings.Repeat("2", 64)},
"referenced_patch_artifact_digests": []any{map[string]any{"hash_alg": "sha256", "hash": strings.Repeat("3", 64)}},
"expected_result_tree_hash": map[string]any{"hash_alg": "sha256", "hash": strings.Repeat("4", 64)},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"context"
"testing"

"github.com/runecode-ai/runecode/internal/brokerapi"
"github.com/runecode-systems/runecode/internal/brokerapi"
)

func TestRunAndSessionCommandsRejectPositionalArguments(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion cmd/runecode-broker/main_cli_provider_setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"strings"
"testing"

"github.com/runecode-ai/runecode/internal/brokerapi"
"github.com/runecode-systems/runecode/internal/brokerapi"
)

func TestProviderSetupDirectUsesTrustedSecretIngressWithoutArgsOrEnv(t *testing.T) {
Expand Down
Loading
Loading