From 055311fec2cae1ec89cade67cff23924113a56f5 Mon Sep 17 00:00:00 2001 From: Celia KHERFALLAH Date: Mon, 16 Feb 2026 11:03:52 +0100 Subject: [PATCH 1/2] feat(opencode): modify the UI to inform the user that, when using the concrete-security, the channel is secure --- packages/opencode/script/build.ts | 2 +- .../src/cli/cmd/tui/routes/session/index.tsx | 18 ++++++++++- .../opencode/src/cli/cmd/tui/util/provider.ts | 16 ++++++++++ .../opencode/test/cli/tui/provider.test.ts | 31 +++++++++++++++++++ user_secure_configuration_example.json | 20 ++++++++++++ 5 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 packages/opencode/src/cli/cmd/tui/util/provider.ts create mode 100644 packages/opencode/test/cli/tui/provider.test.ts create mode 100644 user_secure_configuration_example.json diff --git a/packages/opencode/script/build.ts b/packages/opencode/script/build.ts index f0b3fa828a78..46cf42a92f93 100755 --- a/packages/opencode/script/build.ts +++ b/packages/opencode/script/build.ts @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import solidPlugin from "../node_modules/@opentui/solid/scripts/solid-plugin" +import solidPlugin from "@opentui/solid/bun-plugin" import path from "path" import fs from "fs" import { $ } from "bun" diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 77872eedaddd..dafbe5676d71 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -77,6 +77,7 @@ import { PermissionPrompt } from "./permission" import { QuestionPrompt } from "./question" import { DialogExportOptions } from "../../ui/dialog-export-options" import { formatTranscript } from "../../util/transcript" +import { getSecurityIndicator } from "../../util/provider" import { UI } from "@/cli/ui.ts" addDefaultParsers(parsers.parsers) @@ -1300,7 +1301,22 @@ function AssistantMessage(props: { message: AssistantMessage; parts: Part[]; las ▣{" "} {" "} {Locale.titlecase(props.message.mode)} - · {props.message.modelID} + {(() => { + const indicator = getSecurityIndicator(props.message.providerID, !!props.message.error) + return ( + + {" · "} + {indicator.label} + {props.message.modelID} + + ) + })()} · {Locale.duration(duration())} diff --git a/packages/opencode/src/cli/cmd/tui/util/provider.ts b/packages/opencode/src/cli/cmd/tui/util/provider.ts new file mode 100644 index 000000000000..d7db4b7db61e --- /dev/null +++ b/packages/opencode/src/cli/cmd/tui/util/provider.ts @@ -0,0 +1,16 @@ +/** + * Returns a security indicator label and status for the given provider. + * + * When the provider is "concrete-security", the channel is expected to be + * encrypted end-to-end. If an error occurred during the exchange the + * indicator signals an unsecure state; otherwise it confirms the channel + * is secure. For any other provider, no indicator is shown. + */ +export function getSecurityIndicator(providerID: string, hasError: boolean) { + if (providerID === "concrete-security") { + return hasError + ? { label: "⚠ Unsecure ", status: "error" as const } + : { label: "🔐 Secure ", status: "secure" as const } + } + return { label: "", status: "none" as const } +} diff --git a/packages/opencode/test/cli/tui/provider.test.ts b/packages/opencode/test/cli/tui/provider.test.ts new file mode 100644 index 000000000000..ce42edec6565 --- /dev/null +++ b/packages/opencode/test/cli/tui/provider.test.ts @@ -0,0 +1,31 @@ +/** + * Tests for the security indicator displayed in the session header. + * + * The "concrete-security" provider uses an encrypted channel, so the UI + * shows a visual cue reflecting whether the exchange succeeded (secure) + * or failed (unsecure). Other providers should produce no indicator. + */ +import { describe, expect, test } from "bun:test" +import { getSecurityIndicator } from "../../../src/cli/cmd/tui/util/provider" + +describe("getSecurityIndicator", () => { + // When the provider is "concrete-security" and no error occurred, + // the channel is considered secure. + test("concrete-security without error returns secure", () => { + const result = getSecurityIndicator("concrete-security", false) + expect(result).toEqual({ label: "🔐 Secure ", status: "secure" }) + }) + + // When the provider is "concrete-security" but an error occurred, + // the channel is flagged as unsecure. + test("concrete-security with error returns unsecure", () => { + const result = getSecurityIndicator("concrete-security", true) + expect(result).toEqual({ label: "⚠ Unsecure ", status: "error" }) + }) + + // Non-regression: any other provider should produce no indicator at all. + test("other provider returns empty label", () => { + const result = getSecurityIndicator("anthropic", false) + expect(result).toEqual({ label: "", status: "none" }) + }) +}) diff --git a/user_secure_configuration_example.json b/user_secure_configuration_example.json new file mode 100644 index 000000000000..6e1b11c49570 --- /dev/null +++ b/user_secure_configuration_example.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://opencode.ai/config.json", + "model": "concrete-security/secure-gpt-oss-120b", + "provider": { + "opencode": { "options": {} }, + "concrete-security": { + "npm": "file:///Users/kcelia/Concrete-Security/ratls/ai-provider/dist/index.js", + "api": "https://vllm.concrete-security.com/v1", + "options": { "sdk": "@ai-sdk/anthropic", "apiKey": "dummy-key" }, + "models": { + "secure-gpt-oss-120b": { + "id": "openai/gpt-oss-120b", + "name": "Secure gpt-oss-120b" + } + } + } + }, + "mcp": {}, + "tools": { "github-triage": false, "github-pr-search": false } +} From c32058c918ddb980b53f5d8ea41df9829b0d475c Mon Sep 17 00:00:00 2001 From: Celia KHERFALLAH Date: Mon, 16 Feb 2026 15:46:17 +0100 Subject: [PATCH 2/2] chore(ci): add GitHub Action to auto-sync fork with upstream via rebase --- .github/workflows/sync-upstream.yml | 39 +++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/sync-upstream.yml diff --git a/.github/workflows/sync-upstream.yml b/.github/workflows/sync-upstream.yml new file mode 100644 index 000000000000..e16eb3b08a5e --- /dev/null +++ b/.github/workflows/sync-upstream.yml @@ -0,0 +1,39 @@ +name: Sync Fork with Upstream + +on: + schedule: + - cron: "0 6 * * *" + workflow_dispatch: + +jobs: + sync: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Rebase on upstream + id: rebase + continue-on-error: true + run: | + git remote add upstream https://github.com/anomalyco/opencode.git || true + git fetch upstream + git checkout dev + git rebase upstream/dev + git push origin dev --force-with-lease + + - name: Create PR on conflict + if: steps.rebase.outcome == 'failure' + run: | + git rebase --abort + git checkout -b sync/conflict-$(date +%Y-%m-%d) upstream/dev + git merge origin/dev --no-edit || true + git add -A && git commit -m "sync: conflicts $(date +%Y-%m-%d)" --no-verify + git push origin sync/conflict-$(date +%Y-%m-%d) + gh pr create --base dev --head sync/conflict-$(date +%Y-%m-%d) \ + --title "Sync upstream - conflicts $(date +%Y-%m-%d)" \ + --body "Rebase failed due to conflicts. Please resolve manually." + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}