@yadsh/dsh-qa-surface 0.1.1 → 0.2.0
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/CHANGELOG.md +68 -0
- package/README.md +162 -14
- package/SPEC-dsh-qa-surface.md +600 -96
- package/capability-policy.json +5 -0
- package/compatibility.json +7 -1
- package/cordis.patch.yml +11 -0
- package/docs/ARCHITECTURE.md +49 -7
- package/docs/COMPATIBILITY.md +5 -4
- package/docs/CONFIGURATION.md +96 -2
- package/lib/attestation.js +10 -0
- package/lib/attestation.js.map +1 -0
- package/lib/client/QaConfigController.js +111 -4
- package/lib/client/QaConfigController.js.map +1 -1
- package/lib/client/QaSessionController.js +501 -119
- package/lib/client/QaSessionController.js.map +1 -1
- package/lib/client/QaSurface.js +137 -20
- package/lib/client/QaSurface.js.map +1 -1
- package/lib/client/QaTranscriptAdapter.js +534 -45
- package/lib/client/QaTranscriptAdapter.js.map +1 -1
- package/lib/client/attestation.js +60 -0
- package/lib/client/attestation.js.map +1 -0
- package/lib/client/chat-index.js +86 -0
- package/lib/client/chat-index.js.map +1 -0
- package/lib/client/components/Markdown.js +75 -5
- package/lib/client/components/Markdown.js.map +1 -1
- package/lib/client/components/QaAgentsDrawer.js +40 -0
- package/lib/client/components/QaAgentsDrawer.js.map +1 -0
- package/lib/client/components/QaComposer.js +132 -15
- package/lib/client/components/QaComposer.js.map +1 -1
- package/lib/client/components/QaMessage.js +184 -10
- package/lib/client/components/QaMessage.js.map +1 -1
- package/lib/client/components/QaSidebar.js +124 -0
- package/lib/client/components/QaSidebar.js.map +1 -0
- package/lib/client/components/QaSourcesDrawer.js +46 -0
- package/lib/client/components/QaSourcesDrawer.js.map +1 -0
- package/lib/client/components/QaWorkGroup.js +135 -0
- package/lib/client/components/QaWorkGroup.js.map +1 -0
- package/lib/client/components/VariantSwitcher.js +29 -0
- package/lib/client/components/VariantSwitcher.js.map +1 -0
- package/lib/client/components/format.js +48 -0
- package/lib/client/components/format.js.map +1 -0
- package/lib/client/index.js +77 -34
- package/lib/client/index.js.map +1 -1
- package/lib/client/styles.js +308 -43
- package/lib/client/styles.js.map +1 -1
- package/lib/client/types.js +13 -0
- package/lib/client/types.js.map +1 -0
- package/lib/client/wait-for.js +49 -0
- package/lib/client/wait-for.js.map +1 -0
- package/lib/client.js +8228 -383
- package/lib/client.js.map +1 -1
- package/lib/config.js +61 -9
- package/lib/config.js.map +1 -1
- package/lib/index.js +166 -70
- package/lib/index.js.map +1 -1
- package/lib/lockdown-policy.js +20 -0
- package/lib/lockdown-policy.js.map +1 -0
- package/lib/resolve-config.js +122 -10
- package/lib/resolve-config.js.map +1 -1
- package/lib/secure-session.js +170 -0
- package/lib/secure-session.js.map +1 -0
- package/lib/typert.host.d.ts +3 -0
- package/lib/typert.host.js +191 -0
- package/lib/typert.remote-client.d.ts +24 -0
- package/lib/typert.remote-client.js +129 -0
- package/lib/types/attestation.d.ts +17 -0
- package/lib/types/client/QaConfigController.d.ts +34 -2
- package/lib/types/client/QaSessionController.d.ts +106 -19
- package/lib/types/client/QaSurface.d.ts +5 -4
- package/lib/types/client/QaTranscriptAdapter.d.ts +17 -2
- package/lib/types/client/attestation.d.ts +25 -0
- package/lib/types/client/chat-index.d.ts +28 -0
- package/lib/types/client/components/Markdown.d.ts +7 -3
- package/lib/types/client/components/QaAgentsDrawer.d.ts +25 -0
- package/lib/types/client/components/QaComposer.d.ts +12 -2
- package/lib/types/client/components/QaMessage.d.ts +14 -1
- package/lib/types/client/components/QaSidebar.d.ts +41 -0
- package/lib/types/client/components/QaSourcesDrawer.d.ts +8 -0
- package/lib/types/client/components/QaWorkGroup.d.ts +19 -0
- package/lib/types/client/components/VariantSwitcher.d.ts +19 -0
- package/lib/types/client/components/format.d.ts +9 -0
- package/lib/types/client/index.d.ts +1 -5
- package/lib/types/client/types.d.ts +29 -0
- package/lib/types/client/wait-for.d.ts +11 -0
- package/lib/types/index.d.ts +22 -6
- package/lib/types/lockdown-policy.d.ts +18 -0
- package/lib/types/secure-session.d.ts +22 -0
- package/lib/types/types.d.ts +148 -1
- package/package.json +29 -3
package/SPEC-dsh-qa-surface.md
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# SPEC / Implementation Plan: `dsh-qa-surface`
|
|
2
2
|
|
|
3
|
-
**Status:** Draft / implementation-ready
|
|
4
|
-
**Date:** 2026-09-05
|
|
5
|
-
**
|
|
3
|
+
**Status:** Draft / implementation-ready
|
|
4
|
+
**Date:** 2026-09-05
|
|
5
|
+
**Last updated:** 2026-09-08 — added locked-down / read-only QA execution policy
|
|
6
|
+
**Target:** DeepSeek Harness Web
|
|
6
7
|
**Artifact type:** external DSH UI plugin with a dedicated `/qa` browser surface
|
|
7
8
|
|
|
8
9
|
---
|
|
@@ -232,6 +233,12 @@ No first-party DSH navigation or admin controls should be visible through the QA
|
|
|
232
233
|
- configurable fixed workspace/session target policy;
|
|
233
234
|
- configurable agent preset;
|
|
234
235
|
- configurable model override if explicitly set;
|
|
236
|
+
- **locked-down QA mode enabled by default**;
|
|
237
|
+
- fixed agent preset with no QA-user agent switching;
|
|
238
|
+
- forced `read-only` sandbox mode;
|
|
239
|
+
- forced `approval=never` / no permission escalation;
|
|
240
|
+
- allow-list based tool exposure for QA sessions;
|
|
241
|
+
- no model/workspace/permission/mode/settings switching from the QA surface;
|
|
235
242
|
- safe handling of unsupported interactive states;
|
|
236
243
|
- no leakage of tool calls/reasoning into the QA transcript by default;
|
|
237
244
|
- same-origin use of the normal DSH connection/API stack;
|
|
@@ -274,6 +281,10 @@ The MVP must **not**:
|
|
|
274
281
|
- automatically approve permission requests;
|
|
275
282
|
- automatically answer agent questions;
|
|
276
283
|
- expose admin/settings APIs to unauthenticated users;
|
|
284
|
+
- rely on hidden/disabled UI controls as the only security boundary;
|
|
285
|
+
- allow the QA user to switch agent preset, workspace, model, sandbox mode, approval policy, or permission preset;
|
|
286
|
+
- expose a general-purpose shell/terminal/code-execution tool in the default locked-down preset;
|
|
287
|
+
- expose mutable external-service tools by default;
|
|
277
288
|
- expose raw reasoning by default;
|
|
278
289
|
- expose raw tool arguments/results by default;
|
|
279
290
|
- depend on private DSH component implementation details;
|
|
@@ -440,6 +451,30 @@ Preferred config transport:
|
|
|
440
451
|
|
|
441
452
|
Avoid creating an unauthenticated `/qa-config.json` endpoint.
|
|
442
453
|
|
|
454
|
+
### 10.2 LAN config channel
|
|
455
|
+
|
|
456
|
+
DSH pins settings RPCs to loopback (`settings.*` sits in the gateway's
|
|
457
|
+
privileged method set), so a browser served from a non-loopback bind always
|
|
458
|
+
sees the namespace as `unavailable`. The Host half therefore exposes one
|
|
459
|
+
additional read-only Remote, `qaSurface/describe`, returning the effective
|
|
460
|
+
resolved configuration — the same projection `secureSession` attests against.
|
|
461
|
+
It is the network-neutral answer to responsibility 3: still plugin-scoped,
|
|
462
|
+
still no arbitrary Host config, no secrets, no file paths beyond the
|
|
463
|
+
configured ids, and no admission authority (enforcement stays in
|
|
464
|
+
`secureSession`).
|
|
465
|
+
|
|
466
|
+
Client contract: when the settings namespace is `unavailable` — and only
|
|
467
|
+
then — the browser calls `describe` once per controller lifetime, waits in
|
|
468
|
+
`loading`, and adopts the returned configuration as `ready`; a rejected or
|
|
469
|
+
invalid answer falls back to the client defaults under `unavailable`. A
|
|
470
|
+
readable namespace always wins and keeps delivering live updates.
|
|
471
|
+
|
|
472
|
+
LAN serving itself is a deployment composition concern, not plugin config:
|
|
473
|
+
the shipped `deploy/qa-lan.patch.yml` overlay binds the `webserver` row to
|
|
474
|
+
`0.0.0.0`, and the DSH `/api` browser-trust fence derives the LAN authorities
|
|
475
|
+
on its own. See the README "Serving the QA rig over the LAN" section for the
|
|
476
|
+
deployment responsibilities this creates.
|
|
477
|
+
|
|
443
478
|
---
|
|
444
479
|
|
|
445
480
|
## 11. Configuration model
|
|
@@ -454,10 +489,10 @@ route:
|
|
|
454
489
|
matchChildren: true
|
|
455
490
|
|
|
456
491
|
branding:
|
|
457
|
-
title:
|
|
492
|
+
title: Помощник
|
|
458
493
|
subtitle: ""
|
|
459
|
-
welcomeMessage: "
|
|
460
|
-
placeholder: "
|
|
494
|
+
welcomeMessage: "Чем могу помочь?"
|
|
495
|
+
placeholder: "Задайте вопрос…"
|
|
461
496
|
logoUrl: null
|
|
462
497
|
|
|
463
498
|
session:
|
|
@@ -472,7 +507,7 @@ session:
|
|
|
472
507
|
|
|
473
508
|
ui:
|
|
474
509
|
showHeader: true
|
|
475
|
-
showReset:
|
|
510
|
+
showReset: false
|
|
476
511
|
showStop: true
|
|
477
512
|
showTimestamps: false
|
|
478
513
|
showToolActivity: false
|
|
@@ -480,12 +515,34 @@ ui:
|
|
|
480
515
|
renderMarkdown: true
|
|
481
516
|
maxContentWidth: 900
|
|
482
517
|
|
|
483
|
-
suggestedQuestions:
|
|
518
|
+
suggestedQuestions:
|
|
519
|
+
- "Что ты умеешь?"
|
|
520
|
+
- "С чего начать?"
|
|
521
|
+
- "Помоги разобраться с ошибкой"
|
|
484
522
|
|
|
485
523
|
interaction:
|
|
486
524
|
approvals: blocked
|
|
487
525
|
questions: unsupported
|
|
488
526
|
|
|
527
|
+
lockdown:
|
|
528
|
+
enabled: true
|
|
529
|
+
enforceFixedAgentPreset: true
|
|
530
|
+
enforceFixedWorkspace: true
|
|
531
|
+
enforceFixedModel: true
|
|
532
|
+
sandboxMode: read-only
|
|
533
|
+
approvalPolicy: never
|
|
534
|
+
permissionPreset: qa-read-only
|
|
535
|
+
allowPermissionChanges: false
|
|
536
|
+
allowSlashCommands: false
|
|
537
|
+
allowSettingsMutation: false
|
|
538
|
+
allowSessionReset: false
|
|
539
|
+
allowSessionRename: false
|
|
540
|
+
allowSessionDelete: false
|
|
541
|
+
allowArbitrarySessionOpen: false
|
|
542
|
+
toolPolicy:
|
|
543
|
+
mode: allow-list
|
|
544
|
+
allow: []
|
|
545
|
+
|
|
489
546
|
embedding:
|
|
490
547
|
frameAncestors: null
|
|
491
548
|
```
|
|
@@ -580,7 +637,247 @@ means use DSH deployment/session defaults.
|
|
|
580
637
|
|
|
581
638
|
If both are configured, apply the model selection to the QA session through the public session model-selection path.
|
|
582
639
|
|
|
583
|
-
|
|
640
|
+
In locked-down mode, never render a model picker and do not expose a controller action for model switching. If provider/model are left `null`, operator deployment defaults may still determine the model for newly created sessions; that is an operator-side policy change, not a QA-user choice.
|
|
641
|
+
|
|
642
|
+
|
|
643
|
+
|
|
644
|
+
### 11.6 Locked-down execution policy
|
|
645
|
+
|
|
646
|
+
`/qa` must default to a **capability-reduced execution profile**, not merely a visually simplified UI.
|
|
647
|
+
|
|
648
|
+
The desired invariant is:
|
|
649
|
+
|
|
650
|
+
```text
|
|
651
|
+
QA user can:
|
|
652
|
+
- submit text questions;
|
|
653
|
+
- receive assistant answers;
|
|
654
|
+
- stop the current turn;
|
|
655
|
+
- optionally start a fresh QA session.
|
|
656
|
+
|
|
657
|
+
QA user cannot:
|
|
658
|
+
- change the agent preset;
|
|
659
|
+
- change workspace/cwd;
|
|
660
|
+
- change model/provider/reasoning mode;
|
|
661
|
+
- change permissions/sandbox/approval policy;
|
|
662
|
+
- invoke DSH slash commands;
|
|
663
|
+
- mutate settings;
|
|
664
|
+
- open arbitrary existing sessions;
|
|
665
|
+
- rename/delete sessions;
|
|
666
|
+
- gain a shell/terminal merely because it exists globally;
|
|
667
|
+
- trigger write-capable Jira/GitHub/Confluence/Slack/email/etc. actions;
|
|
668
|
+
- escalate from read-only to a wider sandbox mode.
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
This must be enforced in layers. Hiding selectors is only the presentation layer.
|
|
672
|
+
|
|
673
|
+
#### Layer 1 — fixed session composition
|
|
674
|
+
|
|
675
|
+
For every newly created QA session:
|
|
676
|
+
|
|
677
|
+
- use exactly the configured `session.agentPreset`;
|
|
678
|
+
- use exactly the configured `session.workspaceId`;
|
|
679
|
+
- if model/provider are configured, use exactly those values;
|
|
680
|
+
- refuse to silently fall back to another agent/workspace when the configured value is missing;
|
|
681
|
+
- persist the selected QA session id, but do not persist user-selectable composition overrides.
|
|
682
|
+
|
|
683
|
+
DSH currently treats the agent preset as a per-session composition fact. Existing upstream behavior already prevents changing the preset after a session has produced history; blank sessions may still have a preset choice before the first turn. Therefore the QA controller must create/bind the session with the configured preset and never expose the blank-session preset selector.
|
|
684
|
+
|
|
685
|
+
Reference:
|
|
686
|
+
|
|
687
|
+
- https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-agent-preset/README.md
|
|
688
|
+
- https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-08-03-per-session-agent-presets.md
|
|
689
|
+
|
|
690
|
+
#### Layer 2 — force `read-only` + `approval=never`
|
|
691
|
+
|
|
692
|
+
The locked-down QA policy must pin both independent DSH permission knobs:
|
|
693
|
+
|
|
694
|
+
```yaml
|
|
695
|
+
sandbox: read-only
|
|
696
|
+
approval: never
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
Prefer defining a named deployment preset:
|
|
700
|
+
|
|
701
|
+
```yaml
|
|
702
|
+
permissionPresets:
|
|
703
|
+
presets:
|
|
704
|
+
qa-read-only:
|
|
705
|
+
sandbox: read-only
|
|
706
|
+
approval: never
|
|
707
|
+
name: QA Read Only
|
|
708
|
+
description: No filesystem mutations and no permission escalation.
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
On a **shared operator + QA DSH instance**, do not make `qa-read-only` the process-wide `defaultPreset` merely for this plugin, because that would also change the default permissions of ordinary operator-created sessions. Instead, the QA bootstrap path must select/pin `qa-read-only` on the freshly created blank QA session **before the first prompt is accepted**, then verify the effective sandbox/approval facts.
|
|
712
|
+
|
|
713
|
+
On a **dedicated QA DSH instance**, setting `defaultPreset: qa-read-only` is recommended as an additional fail-safe.
|
|
714
|
+
|
|
715
|
+
The exact surrounding Cordis row/config syntax must be adapted to the target deployment.
|
|
716
|
+
|
|
717
|
+
Important: DSH's shipped permission preset table normally contains `workspace-write` and `danger-full-access`; `qa-read-only` is an explicit custom table entry for this deployment. The underlying knobs are the authoritative enforcement facts.
|
|
718
|
+
|
|
719
|
+
`approval=never` is required because it deterministically rejects operations that request approval instead of presenting an approval UI. The QA surface must never implement an auto-approve path.
|
|
720
|
+
|
|
721
|
+
References:
|
|
722
|
+
|
|
723
|
+
- https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/permission-presets.md
|
|
724
|
+
- https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/approval.md
|
|
725
|
+
- https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/sandbox/sandbox-policy/README.md
|
|
726
|
+
|
|
727
|
+
#### Layer 3 — tool allow-list, not a deny-list
|
|
728
|
+
|
|
729
|
+
`read-only` is **not equivalent to “no side effects.”** It governs file effects enforced by the DSH file sandbox; network and process visibility are outside that sandbox vocabulary. A shell command can still make network requests or trigger external side effects even when filesystem writes are denied.
|
|
730
|
+
|
|
731
|
+
Therefore the default QA preset must use an explicit **allow-list of known read-only tools**.
|
|
732
|
+
|
|
733
|
+
Conceptual policy:
|
|
734
|
+
|
|
735
|
+
```yaml
|
|
736
|
+
lockdown:
|
|
737
|
+
toolPolicy:
|
|
738
|
+
mode: allow-list
|
|
739
|
+
allow:
|
|
740
|
+
- knowledge.search
|
|
741
|
+
- knowledge.read
|
|
742
|
+
- web.search
|
|
743
|
+
- web.fetch
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
The actual names must come from the composed DSH deployment. Do not copy these illustrative names blindly.
|
|
747
|
+
|
|
748
|
+
Prefer allow-list semantics because newly installed global tools are then excluded automatically. DSH has a scoped `ToolRestriction.allow` mechanism for inherited global tools. Note that tools registered directly inside the agent's own scope are intentionally exempt from inherited restrictions, so **the QA agent preset itself must also be reviewed and must not register write-capable tools**.
|
|
749
|
+
|
|
750
|
+
References:
|
|
751
|
+
|
|
752
|
+
- https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/tools.md
|
|
753
|
+
- https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/tools/src/index.ts
|
|
754
|
+
|
|
755
|
+
Default deny category examples:
|
|
756
|
+
|
|
757
|
+
| Capability | Default QA policy | Reason |
|
|
758
|
+
|---|---|---|
|
|
759
|
+
| generic shell / bash / terminal | deny | can create non-filesystem side effects and broad host visibility |
|
|
760
|
+
| generic code runtime | deny | same reason unless a separately constrained pure-compute runtime exists |
|
|
761
|
+
| fs write/edit/move/delete | deny | direct mutation |
|
|
762
|
+
| git commit/push/checkout/reset | deny | repository mutation / remote side effects |
|
|
763
|
+
| Jira create/update/comment/transition | deny | external mutation |
|
|
764
|
+
| Confluence create/update/delete | deny | external mutation |
|
|
765
|
+
| Slack/email send | deny | external mutation |
|
|
766
|
+
| browser/computer-use click/type/submit | deny | arbitrary external side effects |
|
|
767
|
+
| settings/plugin management | deny | can expand capabilities |
|
|
768
|
+
| permission/preset management | deny | can expand capabilities |
|
|
769
|
+
| agent-preset management | deny | can change composition |
|
|
770
|
+
| read-only KB/search/fetch tools | allow only after review | intended QA capability |
|
|
771
|
+
|
|
772
|
+
For MCP, allow-list at the **tool level**, not merely at the server name. A server may expose both read and write actions.
|
|
773
|
+
|
|
774
|
+
#### Layer 4 — no mutation commands or alternate control paths
|
|
775
|
+
|
|
776
|
+
The QA composer must call the plain public prompt path directly and must not expose the general DSH command dispatcher.
|
|
777
|
+
|
|
778
|
+
Default:
|
|
779
|
+
|
|
780
|
+
```yaml
|
|
781
|
+
lockdown:
|
|
782
|
+
allowSlashCommands: false
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
At minimum prevent QA-side use of control paths equivalent to:
|
|
786
|
+
|
|
787
|
+
```text
|
|
788
|
+
/permission ...
|
|
789
|
+
/permissionPresets ...
|
|
790
|
+
agent/preset selectors
|
|
791
|
+
model selectors
|
|
792
|
+
workspace selectors
|
|
793
|
+
settings mutation
|
|
794
|
+
plugin management
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
Do not rely only on filtering strings that start with `/` if the DSH prompt API already provides a command-free prompt submission method. Prefer bypassing command adjudication entirely.
|
|
798
|
+
|
|
799
|
+
#### Layer 5 — controller-side invariant checks
|
|
800
|
+
|
|
801
|
+
`QaSessionController` must verify its effective session state before enabling Send.
|
|
802
|
+
|
|
803
|
+
Conceptual check:
|
|
804
|
+
|
|
805
|
+
```ts
|
|
806
|
+
interface QaLockdownInvariant {
|
|
807
|
+
agentPresetMatches: boolean
|
|
808
|
+
workspaceMatches: boolean
|
|
809
|
+
modelMatches: boolean
|
|
810
|
+
sandboxIsReadOnly: boolean
|
|
811
|
+
approvalIsNever: boolean
|
|
812
|
+
toolPolicyLoaded: boolean
|
|
813
|
+
}
|
|
814
|
+
```
|
|
815
|
+
|
|
816
|
+
If a required invariant cannot be proven, fail closed:
|
|
817
|
+
|
|
818
|
+
```text
|
|
819
|
+
Assistant configuration is unavailable.
|
|
820
|
+
```
|
|
821
|
+
|
|
822
|
+
and disable the composer. Do not continue under a wider or unknown policy.
|
|
823
|
+
|
|
824
|
+
A mismatch should be operator-visible in logs with the expected and actual policy identifiers, but the QA page should not expose sensitive details.
|
|
825
|
+
|
|
826
|
+
#### Layer 6 — host-side guard where public DSH seams allow it
|
|
827
|
+
|
|
828
|
+
UI/controller checks protect normal use but are not enough against another client using the same authenticated DSH APIs. During implementation, use public Host-side DSH enforcement seams where available to bind QA-marked sessions to the locked policy.
|
|
829
|
+
|
|
830
|
+
Preferred mechanisms, in order:
|
|
831
|
+
|
|
832
|
+
1. compose the QA preset so forbidden tools are not mounted at all;
|
|
833
|
+
2. apply scoped tool restrictions to inherited tools;
|
|
834
|
+
3. pin sandbox and approval facts before the first QA prompt;
|
|
835
|
+
4. prefer a Host-side QA session bootstrap operation that creates/binds the session and pins the QA permission facts in one controlled flow, if DSH exposes a clean public seam;
|
|
836
|
+
5. otherwise create a blank session, immediately select `qa-read-only`, verify it, and keep Send disabled until verification succeeds;
|
|
837
|
+
6. add a monotonic `tools/pre-execute` / execution guard for QA sessions if a second server-side side-effect check is needed;
|
|
838
|
+
7. never implement capability expansion through the QA plugin.
|
|
839
|
+
|
|
840
|
+
Do not monkey-patch private RPC handlers merely to create a guard. If DSH has no public seam for a particular mutation path, document that limitation and move the boundary to deployment isolation rather than pretending the browser UI makes it secure.
|
|
841
|
+
|
|
842
|
+
#### Layer 7 — deployment isolation for strong guarantees
|
|
843
|
+
|
|
844
|
+
A `/qa` overlay on the same fully privileged DSH Host is **not a security boundary by itself**. If the same authenticated user can navigate to normal `/`, call privileged DSH APIs, or use another DSH client, hiding controls on `/qa` does not revoke those Host capabilities.
|
|
845
|
+
|
|
846
|
+
For an internal convenience UI, the layered session/tool policy above may be enough.
|
|
847
|
+
|
|
848
|
+
For untrusted or semi-trusted QA users, prefer one of:
|
|
849
|
+
|
|
850
|
+
```text
|
|
851
|
+
Best isolation:
|
|
852
|
+
dedicated QA DSH instance/container
|
|
853
|
+
+ only QA preset/tools mounted
|
|
854
|
+
+ read-only corpus mounts
|
|
855
|
+
+ no developer credentials
|
|
856
|
+
+ restricted network egress
|
|
857
|
+
|
|
858
|
+
Good isolation:
|
|
859
|
+
separate QA auth role/gateway
|
|
860
|
+
+ Host-side API authorization for mutable capabilities
|
|
861
|
+
+ locked QA preset/tool registry
|
|
862
|
+
|
|
863
|
+
Weakest:
|
|
864
|
+
same privileged DSH Host/browser identity
|
|
865
|
+
+ UI controls merely hidden
|
|
866
|
+
```
|
|
867
|
+
|
|
868
|
+
DSH upstream explicitly warns that it is developer-preview software and sandbox/approval controls are risk reducers, not a complete isolation boundary.
|
|
869
|
+
|
|
870
|
+
Reference:
|
|
871
|
+
|
|
872
|
+
- https://github.com/deepseek-ai/deepseek-harness/blob/master/SAFETY.md
|
|
873
|
+
|
|
874
|
+
#### Read isolation caveat
|
|
875
|
+
|
|
876
|
+
Current `read-only` means “no filesystem mutation,” not “the agent can only read its workspace.” Upstream discussion notes that read isolation outside the workspace is not currently guaranteed. Therefore a high-assurance QA deployment should avoid exposing generic shell/fs inspection tools and should mount only the data the QA runtime is intended to read.
|
|
877
|
+
|
|
878
|
+
Reference:
|
|
879
|
+
|
|
880
|
+
- https://github.com/deepseek-ai/deepseek-harness/discussions/492
|
|
584
881
|
|
|
585
882
|
---
|
|
586
883
|
|
|
@@ -601,12 +898,12 @@ Conceptual Cordis inject list:
|
|
|
601
898
|
|
|
602
899
|
```ts
|
|
603
900
|
export const inject = [
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
901
|
+
'slots',
|
|
902
|
+
'sessions',
|
|
903
|
+
'connection',
|
|
904
|
+
'theme',
|
|
608
905
|
// settings service used for qa-surface config
|
|
609
|
-
]
|
|
906
|
+
]
|
|
610
907
|
```
|
|
611
908
|
|
|
612
909
|
Exact service names must be resolved against the target DSH release.
|
|
@@ -622,15 +919,15 @@ shell.overlay
|
|
|
622
919
|
Conceptually:
|
|
623
920
|
|
|
624
921
|
```ts
|
|
625
|
-
ctx.slots.inject(
|
|
922
|
+
ctx.slots.inject('shell.overlay', () =>
|
|
626
923
|
ctx.slots.register(
|
|
627
924
|
{
|
|
628
|
-
name:
|
|
629
|
-
key:
|
|
925
|
+
name: 'shell.overlay',
|
|
926
|
+
key: 'dsh-qa-surface'
|
|
630
927
|
},
|
|
631
928
|
QaSurfaceEntry,
|
|
632
929
|
),
|
|
633
|
-
)
|
|
930
|
+
)
|
|
634
931
|
```
|
|
635
932
|
|
|
636
933
|
The entry remains mounted but returns `null` whenever the route is not active.
|
|
@@ -725,27 +1022,27 @@ UI components consume a plugin-owned interface such as:
|
|
|
725
1022
|
```ts
|
|
726
1023
|
interface QaSessionState {
|
|
727
1024
|
phase:
|
|
728
|
-
|
|
|
729
|
-
|
|
|
730
|
-
|
|
|
731
|
-
|
|
|
732
|
-
|
|
|
733
|
-
|
|
|
734
|
-
|
|
|
735
|
-
|
|
736
|
-
sessionId: string | null
|
|
737
|
-
messages: readonly QaMessage[]
|
|
738
|
-
error: string | null
|
|
739
|
-
canSend: boolean
|
|
740
|
-
canStop: boolean
|
|
1025
|
+
| 'idle'
|
|
1026
|
+
| 'creating'
|
|
1027
|
+
| 'ready'
|
|
1028
|
+
| 'running'
|
|
1029
|
+
| 'reconnecting'
|
|
1030
|
+
| 'blocked'
|
|
1031
|
+
| 'error'
|
|
1032
|
+
|
|
1033
|
+
sessionId: string | null
|
|
1034
|
+
messages: readonly QaMessage[]
|
|
1035
|
+
error: string | null
|
|
1036
|
+
canSend: boolean
|
|
1037
|
+
canStop: boolean
|
|
741
1038
|
}
|
|
742
1039
|
|
|
743
1040
|
interface QaSessionActions {
|
|
744
|
-
ensureSession(): Promise<void
|
|
745
|
-
send(text: string): Promise<void
|
|
746
|
-
stop(): Promise<void
|
|
747
|
-
reset(): Promise<void
|
|
748
|
-
retryConnection(): void
|
|
1041
|
+
ensureSession(): Promise<void>
|
|
1042
|
+
send(text: string): Promise<void>
|
|
1043
|
+
stop(): Promise<void>
|
|
1044
|
+
reset(): Promise<void>
|
|
1045
|
+
retryConnection(): void
|
|
749
1046
|
}
|
|
750
1047
|
```
|
|
751
1048
|
|
|
@@ -758,6 +1055,27 @@ Benefits:
|
|
|
758
1055
|
|
|
759
1056
|
---
|
|
760
1057
|
|
|
1058
|
+
### 15.1 Optional chat-history sidebar
|
|
1059
|
+
|
|
1060
|
+
`ui.showSessionList` (default `false`) renders a minimal sidebar beside the
|
|
1061
|
+
conversation. Contract:
|
|
1062
|
+
|
|
1063
|
+
- the index is per browser: localStorage `<storageKey>:v1:<route>:chats`,
|
|
1064
|
+
session ids only, most recently used first, capped at 50;
|
|
1065
|
+
- rows are the index intersected with the Host session list, so shared-host
|
|
1066
|
+
users never see each other's chats;
|
|
1067
|
+
- switching goes through the same bind + `secureSession` attestation path as
|
|
1068
|
+
restore; a missing id is pruned and reported; an attestation failure keeps
|
|
1069
|
+
the index entry and surfaces the generic configuration error;
|
|
1070
|
+
- `New chat` in the sidebar follows the same `allowSessionReset` gate as the
|
|
1071
|
+
header control; the previous chat stays in the index;
|
|
1072
|
+
- each row carries a two-click delete control: the first click arms it, the
|
|
1073
|
+
second removes the chat from this browser's index (the Host session stays —
|
|
1074
|
+
DSH 0.1.x has no session-deletion seam); deleting the open chat continues
|
|
1075
|
+
in a fresh attested session when resets are allowed;
|
|
1076
|
+
- the sidebar hides below 600px viewports and under `fixed` policy it renders
|
|
1077
|
+
without the new-chat control and never switches.
|
|
1078
|
+
|
|
761
1079
|
## 16. Session creation / restore algorithm
|
|
762
1080
|
|
|
763
1081
|
### 16.1 `browser-persistent`
|
|
@@ -809,10 +1127,22 @@ The DSH Session is the authoritative transcript store.
|
|
|
809
1127
|
|
|
810
1128
|
### 16.3 Reset
|
|
811
1129
|
|
|
812
|
-
|
|
1130
|
+
In default locked-down mode:
|
|
1131
|
+
|
|
1132
|
+
```yaml
|
|
1133
|
+
lockdown:
|
|
1134
|
+
allowSessionReset: false
|
|
1135
|
+
ui:
|
|
1136
|
+
showReset: false
|
|
1137
|
+
```
|
|
1138
|
+
|
|
1139
|
+
so the QA user gets one persistent conversation and cannot create arbitrary additional sessions from the surface.
|
|
1140
|
+
|
|
1141
|
+
If an operator explicitly enables Reset, it means:
|
|
813
1142
|
|
|
814
1143
|
- stop active generation if needed;
|
|
815
1144
|
- create a fresh DSH Session using the configured workspace/preset;
|
|
1145
|
+
- apply and verify the locked QA permission policy before enabling Send;
|
|
816
1146
|
- switch controller binding to it;
|
|
817
1147
|
- replace stored session id;
|
|
818
1148
|
- do not delete the old DSH Session automatically.
|
|
@@ -902,23 +1232,23 @@ Output:
|
|
|
902
1232
|
```ts
|
|
903
1233
|
type QaMessage =
|
|
904
1234
|
| {
|
|
905
|
-
id: string
|
|
906
|
-
role:
|
|
907
|
-
text: string
|
|
908
|
-
status:
|
|
1235
|
+
id: string
|
|
1236
|
+
role: 'user'
|
|
1237
|
+
text: string
|
|
1238
|
+
status: 'committed'
|
|
909
1239
|
}
|
|
910
1240
|
| {
|
|
911
|
-
id: string
|
|
912
|
-
role:
|
|
913
|
-
text: string
|
|
914
|
-
status:
|
|
1241
|
+
id: string
|
|
1242
|
+
role: 'assistant'
|
|
1243
|
+
text: string
|
|
1244
|
+
status: 'streaming' | 'committed' | 'failed'
|
|
915
1245
|
}
|
|
916
1246
|
| {
|
|
917
|
-
id: string
|
|
918
|
-
role:
|
|
919
|
-
text: string
|
|
920
|
-
status:
|
|
921
|
-
}
|
|
1247
|
+
id: string
|
|
1248
|
+
role: 'system'
|
|
1249
|
+
text: string
|
|
1250
|
+
status: 'info' | 'error'
|
|
1251
|
+
}
|
|
922
1252
|
```
|
|
923
1253
|
|
|
924
1254
|
### 18.1 Visible by default
|
|
@@ -932,7 +1262,8 @@ Render:
|
|
|
932
1262
|
|
|
933
1263
|
### 18.2 Hidden by default
|
|
934
1264
|
|
|
935
|
-
|
|
1265
|
+
Unless the corresponding operator-controlled work-detail option is enabled, do
|
|
1266
|
+
not render:
|
|
936
1267
|
|
|
937
1268
|
- reasoning chunks;
|
|
938
1269
|
- tool call arguments;
|
|
@@ -953,16 +1284,22 @@ Optional config:
|
|
|
953
1284
|
```yaml
|
|
954
1285
|
ui:
|
|
955
1286
|
showToolActivity: true
|
|
1287
|
+
showReasoning: true
|
|
956
1288
|
```
|
|
957
1289
|
|
|
958
|
-
|
|
1290
|
+
projects one work disclosure for each DSH turn. While the turn is running the
|
|
1291
|
+
disclosure is expanded and streams available reasoning/tool state. Once the
|
|
1292
|
+
turn completes it collapses before the final answer to a duration summary such
|
|
1293
|
+
as:
|
|
959
1294
|
|
|
960
1295
|
```text
|
|
961
|
-
|
|
962
|
-
Working…
|
|
1296
|
+
Worked for 1m 24s
|
|
963
1297
|
```
|
|
964
1298
|
|
|
965
|
-
|
|
1299
|
+
Expanding it shows reasoning, intermediate assistant progress, and tool rows.
|
|
1300
|
+
Tool rows may independently reveal their formatted arguments and results.
|
|
1301
|
+
These flags are presentation-only: they must not add tools, weaken
|
|
1302
|
+
`lockdown.toolPolicy`, or expose system/context events and raw Host failures.
|
|
966
1303
|
|
|
967
1304
|
---
|
|
968
1305
|
|
|
@@ -1029,9 +1366,13 @@ interaction:
|
|
|
1029
1366
|
|
|
1030
1367
|
Recommended deployment architecture:
|
|
1031
1368
|
|
|
1032
|
-
-
|
|
1033
|
-
-
|
|
1034
|
-
-
|
|
1369
|
+
- force the QA session to the dedicated `qa-read-only` permission bundle;
|
|
1370
|
+
- force `approval=never`;
|
|
1371
|
+
- remove tools that require escalation rather than allowing an approval flow;
|
|
1372
|
+
- use an allow-list of reviewed read-only tools;
|
|
1373
|
+
- grant no mutable external-service permissions to the QA agent.
|
|
1374
|
+
|
|
1375
|
+
In locked-down mode, an approval request is treated as a policy/configuration failure or an unsupported operation, not as something the QA user may approve.
|
|
1035
1376
|
|
|
1036
1377
|
If the Session enters an unsupported pending interaction state:
|
|
1037
1378
|
|
|
@@ -1100,14 +1441,14 @@ Map internal failures to QA-safe UI errors.
|
|
|
1100
1441
|
|
|
1101
1442
|
Examples:
|
|
1102
1443
|
|
|
1103
|
-
| Internal class
|
|
1104
|
-
|
|
1105
|
-
| session creation rejected
|
|
1106
|
-
| prompt rejected
|
|
1107
|
-
| model route unavailable
|
|
1108
|
-
| connection lost
|
|
1109
|
-
| unsupported approval
|
|
1110
|
-
| malformed persisted session id | silently clear and create a new session
|
|
1444
|
+
| Internal class | QA message |
|
|
1445
|
+
|---|---|
|
|
1446
|
+
| session creation rejected | "Unable to start a chat." |
|
|
1447
|
+
| prompt rejected | "Your message could not be sent." |
|
|
1448
|
+
| model route unavailable | "The assistant is temporarily unavailable." |
|
|
1449
|
+
| connection lost | "Connection lost. Reconnecting…" |
|
|
1450
|
+
| unsupported approval | "This request requires operator interaction." |
|
|
1451
|
+
| malformed persisted session id | silently clear and create a new session |
|
|
1111
1452
|
|
|
1112
1453
|
Never render:
|
|
1113
1454
|
|
|
@@ -1216,6 +1557,35 @@ If iframe embedding is later enabled:
|
|
|
1216
1557
|
|
|
1217
1558
|
---
|
|
1218
1559
|
|
|
1560
|
+
### 26.5 Capability-change endpoints
|
|
1561
|
+
|
|
1562
|
+
The QA browser bundle must not intentionally call mutable control-plane APIs for:
|
|
1563
|
+
|
|
1564
|
+
- settings writes;
|
|
1565
|
+
- plugin enable/disable/config changes;
|
|
1566
|
+
- agent preset authoring/deletion/default changes;
|
|
1567
|
+
- permission preset switching;
|
|
1568
|
+
- sandbox mode changes;
|
|
1569
|
+
- approval policy changes;
|
|
1570
|
+
- workspace rebinding;
|
|
1571
|
+
- model/provider switching;
|
|
1572
|
+
- arbitrary session deletion/rename/import.
|
|
1573
|
+
|
|
1574
|
+
If a public read API is needed to verify the effective state, use it read-only and project only the minimum information required by the QA controller.
|
|
1575
|
+
|
|
1576
|
+
### 26.6 UI disabled state is defense-in-depth only
|
|
1577
|
+
|
|
1578
|
+
For every forbidden control that might accidentally appear because of future DSH composition changes:
|
|
1579
|
+
|
|
1580
|
+
- do not render it in the QA component;
|
|
1581
|
+
- if inherited UI becomes reachable, make it inaccessible/inert;
|
|
1582
|
+
- keep controller actions absent, not merely disabled;
|
|
1583
|
+
- add E2E tests proving no selector/menu/command can alter the locked policy.
|
|
1584
|
+
|
|
1585
|
+
The absence of a button is not considered enforcement.
|
|
1586
|
+
|
|
1587
|
+
---
|
|
1588
|
+
|
|
1219
1589
|
## 27. Operator vs QA-user separation
|
|
1220
1590
|
|
|
1221
1591
|
Desired deployment:
|
|
@@ -1311,8 +1681,27 @@ Illustrative only; exact Loader syntax must match the deployment.
|
|
|
1311
1681
|
policy: browser-persistent
|
|
1312
1682
|
workspaceId: company-knowledge
|
|
1313
1683
|
agentPreset: qa-assistant
|
|
1684
|
+
provider: null
|
|
1685
|
+
model: null
|
|
1686
|
+
lockdown:
|
|
1687
|
+
enabled: true
|
|
1688
|
+
enforceFixedAgentPreset: true
|
|
1689
|
+
enforceFixedWorkspace: true
|
|
1690
|
+
enforceFixedModel: true
|
|
1691
|
+
sandboxMode: read-only
|
|
1692
|
+
approvalPolicy: never
|
|
1693
|
+
permissionPreset: qa-read-only
|
|
1694
|
+
allowPermissionChanges: false
|
|
1695
|
+
allowSlashCommands: false
|
|
1696
|
+
allowSettingsMutation: false
|
|
1697
|
+
allowSessionReset: false
|
|
1698
|
+
allowArbitrarySessionOpen: false
|
|
1699
|
+
toolPolicy:
|
|
1700
|
+
mode: allow-list
|
|
1701
|
+
allow:
|
|
1702
|
+
- <reviewed-read-only-tool>
|
|
1314
1703
|
ui:
|
|
1315
|
-
showReset:
|
|
1704
|
+
showReset: false
|
|
1316
1705
|
showStop: true
|
|
1317
1706
|
showToolActivity: false
|
|
1318
1707
|
showReasoning: false
|
|
@@ -1331,11 +1720,13 @@ Prefer a DSH agent preset conceptually like:
|
|
|
1331
1720
|
```text
|
|
1332
1721
|
qa-assistant
|
|
1333
1722
|
├── system prompt / persona
|
|
1334
|
-
├── knowledge
|
|
1335
|
-
├── Jira/Confluence MCP if
|
|
1723
|
+
├── reviewed read-only knowledge/search tools only
|
|
1724
|
+
├── read-only Jira/Confluence MCP actions only, if needed
|
|
1336
1725
|
├── selected skills
|
|
1337
|
-
├──
|
|
1338
|
-
|
|
1726
|
+
├── no shell / terminal / generic code runtime by default
|
|
1727
|
+
├── no mutating external-service actions
|
|
1728
|
+
├── qa-read-only permission policy
|
|
1729
|
+
└── fixed model policy, if deployment requires it
|
|
1339
1730
|
```
|
|
1340
1731
|
|
|
1341
1732
|
This makes the same assistant reusable from:
|
|
@@ -1486,7 +1877,10 @@ Use an existing external browser UI plugin as a packaging reference if necessary
|
|
|
1486
1877
|
- invalid `/api` route rejected;
|
|
1487
1878
|
- invalid session policy rejected;
|
|
1488
1879
|
- fixed policy requires session id;
|
|
1489
|
-
- empty title/placeholder behavior defined
|
|
1880
|
+
- empty title/placeholder behavior defined;
|
|
1881
|
+
- lockdown defaults to enabled;
|
|
1882
|
+
- locked-down default disables session reset;
|
|
1883
|
+
- `qa-read-only` selection is required before first prompt when lockdown is enabled.
|
|
1490
1884
|
|
|
1491
1885
|
#### Route controller
|
|
1492
1886
|
|
|
@@ -1507,7 +1901,11 @@ Use an existing external browser UI plugin as a packaging reference if necessary
|
|
|
1507
1901
|
- accepted send clears draft at correct time;
|
|
1508
1902
|
- rejected send preserves draft;
|
|
1509
1903
|
- stop calls public DSH cancellation path;
|
|
1510
|
-
- unsupported pending interaction blocks composer
|
|
1904
|
+
- unsupported pending interaction blocks composer;
|
|
1905
|
+
- agent/workspace/model mismatch blocks composer;
|
|
1906
|
+
- non-`read-only` sandbox state blocks composer;
|
|
1907
|
+
- approval policy other than `never` blocks composer;
|
|
1908
|
+
- lockdown config cannot be weakened through browser-local state.
|
|
1511
1909
|
|
|
1512
1910
|
#### Transcript adapter
|
|
1513
1911
|
|
|
@@ -1543,17 +1941,55 @@ Verify:
|
|
|
1543
1941
|
7. tool execution can occur without tool details becoming visible;
|
|
1544
1942
|
8. reload restores the same session under browser-persistent policy;
|
|
1545
1943
|
9. normal DSH UI can inspect the QA-created session;
|
|
1546
|
-
10. `/qa` does not open a second server/connection stack
|
|
1944
|
+
10. `/qa` does not open a second server/connection stack;
|
|
1945
|
+
11. every QA session starts with the configured agent preset;
|
|
1946
|
+
12. every QA session starts/effectively runs as `read-only`;
|
|
1947
|
+
13. approval policy is `never`;
|
|
1948
|
+
14. model/workspace selectors are absent;
|
|
1949
|
+
15. permission selectors/commands are absent;
|
|
1950
|
+
16. a denied write attempt cannot escalate;
|
|
1951
|
+
17. a newly installed global tool not present in the allow-list is not visible to the QA agent.
|
|
1547
1952
|
|
|
1548
|
-
### 37.4 Security tests
|
|
1953
|
+
### 37.4 Security / lockdown tests
|
|
1549
1954
|
|
|
1550
1955
|
- route does not weaken `/api` trust checks;
|
|
1551
1956
|
- config endpoint/settings do not leak secrets;
|
|
1552
1957
|
- raw tool result not visible;
|
|
1553
1958
|
- stack traces not visible;
|
|
1554
1959
|
- unsupported approval not auto-approved;
|
|
1960
|
+
- `approval=never` rejects escalation deterministically;
|
|
1961
|
+
- sandbox effective mode remains `read-only`;
|
|
1962
|
+
- QA user cannot invoke `/permission` or equivalent command dispatch;
|
|
1963
|
+
- QA user cannot change agent preset, workspace, provider, model, or reasoning mode;
|
|
1964
|
+
- QA user cannot mutate DSH settings/plugin config;
|
|
1965
|
+
- QA user cannot reset/start additional sessions when `allowSessionReset=false`;
|
|
1966
|
+
- QA user cannot open arbitrary existing sessions when `allowArbitrarySessionOpen=false`;
|
|
1967
|
+
- write/edit/delete filesystem tools are absent or denied;
|
|
1968
|
+
- shell/terminal/code-runtime are absent by default;
|
|
1969
|
+
- mutable MCP actions are absent;
|
|
1970
|
+
- allow-listed MCP read actions still work;
|
|
1971
|
+
- adding a new global write-capable tool does not implicitly expose it to QA;
|
|
1972
|
+
- a preset-local tool is reviewed separately because scoped registrations may bypass inherited `ToolRestriction`;
|
|
1973
|
+
- direct malformed/browser-local attempts to weaken lockdown fail closed;
|
|
1555
1974
|
- cross-origin behavior remains blocked unless deployment explicitly changes it.
|
|
1556
1975
|
|
|
1976
|
+
### 37.5 Side-effect regression suite
|
|
1977
|
+
|
|
1978
|
+
Maintain a table of every tool visible to `qa-assistant` and classify it:
|
|
1979
|
+
|
|
1980
|
+
```text
|
|
1981
|
+
read-only / pure
|
|
1982
|
+
external-read
|
|
1983
|
+
filesystem-write
|
|
1984
|
+
external-write
|
|
1985
|
+
privilege/control-plane
|
|
1986
|
+
unknown
|
|
1987
|
+
```
|
|
1988
|
+
|
|
1989
|
+
CI must fail when a visible QA tool is `filesystem-write`, `external-write`, `privilege/control-plane`, or `unknown` unless the spec/config is intentionally updated and reviewed.
|
|
1990
|
+
|
|
1991
|
+
This guards against future plugin installs silently expanding the QA agent's capability surface.
|
|
1992
|
+
|
|
1557
1993
|
### 37.5 Mobile tests
|
|
1558
1994
|
|
|
1559
1995
|
At minimum test:
|
|
@@ -1804,17 +2240,61 @@ Mitigation:
|
|
|
1804
2240
|
|
|
1805
2241
|
---
|
|
1806
2242
|
|
|
2243
|
+
### Risk: `read-only` is mistaken for “no side effects”
|
|
2244
|
+
|
|
2245
|
+
DSH's read-only sandbox covers file mutation, not all process/network effects.
|
|
2246
|
+
|
|
2247
|
+
Mitigation:
|
|
2248
|
+
|
|
2249
|
+
- deny generic shell/terminal/code runtime by default;
|
|
2250
|
+
- explicit tool allow-list;
|
|
2251
|
+
- tool-by-tool MCP review;
|
|
2252
|
+
- `approval=never`;
|
|
2253
|
+
- optional network egress restrictions at container/proxy level.
|
|
2254
|
+
|
|
2255
|
+
### Risk: QA user can reach normal DSH Web
|
|
2256
|
+
|
|
2257
|
+
If `/` and `/qa` share the same privileged identity, the user may bypass UI lockdown by opening the normal operator surface.
|
|
2258
|
+
|
|
2259
|
+
Mitigation:
|
|
2260
|
+
|
|
2261
|
+
- do not claim `/qa` alone is an authorization boundary;
|
|
2262
|
+
- for untrusted users use separate auth roles/gateway or a dedicated QA DSH instance;
|
|
2263
|
+
- preferably expose only the QA surface to the QA audience.
|
|
2264
|
+
|
|
2265
|
+
### Risk: global plugin installation expands tool surface
|
|
2266
|
+
|
|
2267
|
+
Mitigation:
|
|
2268
|
+
|
|
2269
|
+
- allow-list inherited tools;
|
|
2270
|
+
- inspect preset-local registrations separately;
|
|
2271
|
+
- CI capability inventory;
|
|
2272
|
+
- fail closed on unknown tools where practical.
|
|
2273
|
+
|
|
2274
|
+
### Risk: read access is broader than intended
|
|
2275
|
+
|
|
2276
|
+
Current DSH read-only mode does not imply workspace-only read isolation.
|
|
2277
|
+
|
|
2278
|
+
Mitigation:
|
|
2279
|
+
|
|
2280
|
+
- no generic shell/fs browsing in the default QA preset;
|
|
2281
|
+
- dedicated read-only corpus/workspace;
|
|
2282
|
+
- minimal container mounts;
|
|
2283
|
+
- dedicated QA container for high-assurance deployments.
|
|
2284
|
+
|
|
2285
|
+
---
|
|
2286
|
+
|
|
1807
2287
|
## 43. Future evolution
|
|
1808
2288
|
|
|
1809
2289
|
Potential roadmap:
|
|
1810
2290
|
|
|
1811
2291
|
```text
|
|
1812
|
-
0.1 full-screen /qa overlay + one DSH session
|
|
1813
|
-
0.2 settings + branding + suggested questions
|
|
1814
|
-
0.3
|
|
1815
|
-
0.4 attachments +
|
|
1816
|
-
0.5 iframe/embed SDK
|
|
1817
|
-
1.0 dedicated qa profile/bundle option
|
|
2292
|
+
0.1 full-screen /qa overlay + one DSH session + hard lockdown
|
|
2293
|
+
0.2 settings + branding + suggested questions + capability inventory
|
|
2294
|
+
0.3 read-only sources/citations + optional supported questions UI
|
|
2295
|
+
0.4 attachments + feedback (without capability escalation)
|
|
2296
|
+
0.5 iframe/embed SDK + auth-role integration
|
|
2297
|
+
1.0 dedicated qa profile/bundle / isolated QA deployment option
|
|
1818
2298
|
```
|
|
1819
2299
|
|
|
1820
2300
|
Long term the project can become a reusable **DSH-powered assistant frontend** rather than merely an alternative theme.
|
|
@@ -1837,43 +2317,65 @@ Current architecture was checked against upstream DeepSeek Harness sources/docs
|
|
|
1837
2317
|
|
|
1838
2318
|
Key references:
|
|
1839
2319
|
|
|
1840
|
-
- DeepSeek Harness repository / developer-preview status
|
|
2320
|
+
- DeepSeek Harness repository / developer-preview status
|
|
1841
2321
|
https://github.com/deepseek-ai/deepseek-harness
|
|
1842
2322
|
|
|
1843
|
-
- Web app bundle composition (`dsh-base` + browser roster)
|
|
2323
|
+
- Web app bundle composition (`dsh-base` + browser roster)
|
|
1844
2324
|
https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/bundle/web-app/cordis.patch.yml
|
|
1845
2325
|
|
|
1846
|
-
- Web app bundle README
|
|
2326
|
+
- Web app bundle README
|
|
1847
2327
|
https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/bundle/web-app/README.md
|
|
1848
2328
|
|
|
1849
|
-
- Client modules / `dsh.client` / `window.__DSH_BOOT__`
|
|
2329
|
+
- Client modules / `dsh.client` / `window.__DSH_BOOT__`
|
|
1850
2330
|
https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/client-modules.md
|
|
1851
2331
|
|
|
1852
|
-
- Host webserver route/fallback model
|
|
2332
|
+
- Host webserver route/fallback model
|
|
1853
2333
|
https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/host/webserver/README.md
|
|
1854
2334
|
|
|
1855
|
-
- SPA frontend-static fallback
|
|
2335
|
+
- SPA frontend-static fallback
|
|
1856
2336
|
https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/host/frontend-static/README.md
|
|
1857
2337
|
|
|
1858
|
-
- Client runtime / Host-born sessions
|
|
2338
|
+
- Client runtime / Host-born sessions
|
|
1859
2339
|
https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/runtime/README.md
|
|
1860
2340
|
|
|
1861
|
-
- Session Controller
|
|
2341
|
+
- Session Controller
|
|
1862
2342
|
https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/api/session-controller/README.md
|
|
1863
2343
|
|
|
1864
|
-
-
|
|
2344
|
+
- Sandbox policy / `read-only` semantics
|
|
2345
|
+
https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/sandbox/sandbox-policy/README.md
|
|
2346
|
+
|
|
2347
|
+
- Approval policy / `never` fail-closed behavior
|
|
2348
|
+
https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/approval.md
|
|
2349
|
+
|
|
2350
|
+
- Permission presets (`sandbox` + `approval`)
|
|
2351
|
+
https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/permission-presets.md
|
|
2352
|
+
|
|
2353
|
+
- Tool restrictions / allow-list semantics
|
|
2354
|
+
https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/tools.md
|
|
2355
|
+
|
|
2356
|
+
- Agent preset session semantics
|
|
2357
|
+
https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-agent-preset/README.md
|
|
2358
|
+
|
|
2359
|
+
- DSH safety limitations
|
|
2360
|
+
https://github.com/deepseek-ai/deepseek-harness/blob/master/SAFETY.md
|
|
2361
|
+
|
|
2362
|
+
- Current read-isolation limitation discussion
|
|
2363
|
+
https://github.com/deepseek-ai/deepseek-harness/discussions/492
|
|
2364
|
+
|
|
2365
|
+
|
|
2366
|
+
- Web client slots
|
|
1865
2367
|
https://deepseek-harness.github.io/deepseek-harness/en/reference/subsystems/slots
|
|
1866
2368
|
|
|
1867
|
-
- Conversation slot contract / `conversation.session`
|
|
2369
|
+
- Conversation slot contract / `conversation.session`
|
|
1868
2370
|
https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-conversation/src/client/contract/slots.ts
|
|
1869
2371
|
|
|
1870
|
-
- UI layout shell / `shell.overlay`
|
|
2372
|
+
- UI layout shell / `shell.overlay`
|
|
1871
2373
|
https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-layout/README.md
|
|
1872
2374
|
|
|
1873
|
-
- Web client package rules / new UI plugin checklist
|
|
2375
|
+
- Web client package rules / new UI plugin checklist
|
|
1874
2376
|
https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/AGENTS.md
|
|
1875
2377
|
|
|
1876
|
-
- Settings-card cookbook / external dual-face plugin pattern
|
|
2378
|
+
- Settings-card cookbook / external dual-face plugin pattern
|
|
1877
2379
|
https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/cookbook/adding-a-settings-card.md
|
|
1878
2380
|
|
|
1879
2381
|
### Upstream limitation worth tracking
|
|
@@ -1914,8 +2416,10 @@ At the time of writing there is no generic first-class global-page extension con
|
|
|
1914
2416
|
textarea / Send
|
|
1915
2417
|
```
|
|
1916
2418
|
|
|
1917
|
-
The core architectural
|
|
2419
|
+
The core architectural principles are:
|
|
1918
2420
|
|
|
1919
2421
|
> **Replace the presentation, not the harness.**
|
|
1920
2422
|
|
|
1921
|
-
|
|
2423
|
+
> **Remove capabilities at the runtime/tool-policy layer; hiding buttons is only defense in depth.**
|
|
2424
|
+
|
|
2425
|
+
`dsh-qa-surface` should be a thin QA/browser surface over the existing DSH runtime, with `/qa` acting as a dedicated end-user presentation while `/` remains the full operator/developer interface. In locked-down deployments, QA sessions must be bound to a fixed composition and a fail-closed read-only capability set.
|