Skip to content

JetBrains support: single local plugin via EelApi (Kotlin/BouncyCastle port) #81

Description

@dnegstad

Tracking issue for JetBrains IDE support, capturing the design discussion from #74. That PR extracted the shared cert layer, added the hostCertGenerator backend model (dotnet-if-available, native otherwise), and made the macOS dotnet dev-certs disk cache loadable — all of which transfer to this work as specifications. An earlier dcdc host CLI was dropped from #74 because it conflicted with VS Code's per-user configuration model and, being Node-based, wouldn't have simplified a JetBrains integration anyway.

Why the JetBrains architecture is favorable now

JetBrains rebuilt Dev Containers in 2026.1: the full IDE runs locally with a small agent (ijent) inside the container, and plugin code reaches into the container through EelApi (process execution, filesystem, ports, path translation, OS info). No IDE backend runs in the container.

This inverts VS Code's model in our favor. Our host/workspace extension pair exists because VS Code separates the process with local-machine access from the process with container-filesystem access. In JetBrains' model, one ordinary plugin has both:

VS Code component JetBrains equivalent
Host extension (generate, OS trust, consent UI) The plugin itself — local JVM: spawn security / certutil.exe / pwsh / dotnet dev-certs, show dialogs
Workspace extension (write .NET store, c_rehash, trust dir) Same plugin via EelApi — write files into the container, exec in it
executeCommand cross-host IPC Nothing — single process

Proposed design

Single Kotlin plugin, no split-mode modules. Full port mirroring the VS Code TS extension:

  • Backend model identical to Extract shared cert layer; hostCertGenerator setting + macOS PFX support #74's hostCertGenerator: a Kotlin selectBackend with a DotnetBackend (shell dotnet dev-certs https --trust, discover the cert from the platform store) preferred where it helps, and a NativeBackend using BouncyCastle for X.509 generation + PKCS#12/PBES2 export (same dev-cert OID marker, SAN entries, key parameters as dotnet dev-certs).
  • Container side mirrors certInstaller.ts: write ~/.dotnet/corefx/cryptography/x509stores/{my,root} and the c_rehash'd ~/.aspnet/dev-certs/trust/ directory directly via EelApi's filesystem API. The bash fallback installer (devcontainer-dev-certs-install) stays the minimally-supported no-IDE escape hatch, not a dependency of the plugin — one canonical implementation per IDE, no coupling to openssl/jq presence in the base image.
  • Delivery: the devcontainer feature adds customizations.jetbrains.plugins next to customizations.vscode.extensions. Everything else about the feature is already editor-agnostic.
  • First target: Rider (natural .NET audience), but the plugin should be platform-generic.

Specifications that transfer from #74 (code doesn't, knowledge does)

  • macOS: aspnetcore's MacOSCertificateManager writes the disk cache with legacy 3DES PBE (OID 1.2.840.113549.1.12.1.3). BouncyCastle reads legacy 3DES PKCS#12 natively, so the JVM port gets this for free — no equivalent of pkcs12LegacyPbe.ts needed. The CI test in Extract shared cert layer; hostCertGenerator setting + macOS PFX support #74 (dotnetMacosCache.integration.test.ts) fires when aspnetcore switches to PBES2.
  • Windows: resolve executables through PATH, never cwd-first (resolveSafeExecPath semantics); cache only positive pwsh probe results.
  • macOS: untrust before delete in keychain removal, with the cert file (not keychain path as positional).
  • Empty-password PKCS#12 has two encodings (.NET bare-empty vs OpenSSL UTF-16BE null-terminated) — relevant if the plugin ever writes/reads both sources.
  • Linux: dotnet dev-certs --trust does not touch NSS DBs; supplement with our NSS trust step and surface failures (no silent fall-through).
  • Reverse sync (syncContainerCert): push public cert only, host revalidates (dev-cert OID, version, validity, local-only SAN restriction), consent modal before trust. EelApi can read the container's X509 store directly, so this is simpler than the VS Code version.

Open questions to validate on a real IDE before committing

  1. EelApi process-exec + filesystem access from a third-party plugin inside a dev container (docs are new; API only recently stabilized).
  2. Whether customizations.jetbrains.plugins installs into the local IDE in the 2026.1 model (the docs were written for the older backend-in-container flow).
  3. Version floor: EelApi-based Dev Containers is 2026.1+. Decide whether to also support the older split-mode/remote-backend flow (frontend/backend modules + @Rpc) — feasible but against the API's grain (docs steer process execution to the backend; frontend plugin sync requires marketplace publication) — or declare it out of scope initially.
  4. Marketplace publication + signing pipeline for the plugin (parallel to the VSIX attestation flow in release-feature.yml).
  5. Coexistence with the VS Code extensions on the same host: both discover/reuse the same cert from the platform store keyed by thumbprint, so they should converge rather than conflict — verify no consent-prompt double-fire.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions