Skip to content

feat(plugin): support sandbox manifest fields (sandbox / allowed_hosts / permissions)#1447

Open
nameless-mc wants to merge 18 commits into
mainfrom
feat/plugin-sandbox-fields
Open

feat(plugin): support sandbox manifest fields (sandbox / allowed_hosts / permissions)#1447
nameless-mc wants to merge 18 commits into
mainfrom
feat/plugin-sandbox-fields

Conversation

@nameless-mc
Copy link
Copy Markdown
Contributor

Why

Support three new optional manifest fields (sandbox, allowed_hosts, permissions) across plugin pack / plugin info / plugin upload, so authors can package and inspect sandbox-aware plugins.

Note: Depends on the upcoming release of @kintone/plugin-manifest-validator with the new sandbox fields. The dependency specifier on this branch is not yet pinned to the new version, so CI will fail on install until the validator is published. Local verification uses a pnpm.overrides link against a sibling validator worktree (not included in this PR).

What

  • ManifestV1JsonObject gains three optional fields (sandbox, allowed_hosts, permissions).
  • ManifestInterface gains three accessors (sandbox, allowedHosts, permissions) plus a shared ManifestPermissions type. ManifestV1 forwards the raw manifest values; ManifestV2 returns undefined for sandbox by design (v2 does not define it) and forwards its existing allowed_hosts / permissions fields for interface conformance. v2's inline permissions type is kept to minimize changes to v2.
  • plugin info: when any of sandbox / allowed_hosts / permissions is defined in the manifest, print all four sandbox-related lines together. Sandbox-unaware plugins (none of the three fields defined) skip the block entirely. JSON output mirrors manifest naming (sandbox, allowed_hosts, permissions) and omits absent keys.
  • plugin upload: installation summary follows the same "all four lines together" rule as plugin info.
  • (not set) is used when the parent field is absent from the manifest; (none) is used when the parent is declared but has no entries.
  • Validation: integration test using a new plugin-sandbox-valid manifest fixture. Negative cases are covered at the validator layer, so only a positive fixture lives here.
  • E2E: features/plugin/pack.feature gains a sandbox pack scenario and a plugin info output-pattern scenario, backed by a new features/assets/plugin_project_sandbox/ asset bundle.
  • Docs (hidden, unlisted: true) added at website/docs/guide/experimental/sandbox.md and the Japanese equivalent, describing the fields, required-when-sandbox behavior, and command output.
  • Domain-specific URL rules (IP literal rejection, trailing-slash-only rejection, cybozu domain exclusion, permission value existence checks) are out of scope for cli-kintone; it only checks the structural form inherited from the validator, and the rest is expected to be enforced at runtime by kintone itself.

Output examples

plugin info (plain) — sandbox-aware plugin:

id: <plugin id>
name: hello-kintone-sandbox
version: 1
description: Sandbox-enabled plugin sample.
homepage: https://example.com/en/
sandbox: true
allowed_hosts: https://example.com, wss://example.com/ws/*
permissions.js_api: app:read, network:connect
permissions.rest_api: app_record:read

plugin info (plain) — sandbox-unaware plugin (the block is omitted entirely):

id: <plugin id>
name: sample-plugin
version: 1
description: (not set)
homepage: (not set)

plugin info (json) — only keys present in the manifest are emitted:

{
  "id": "<plugin id>",
  "name": "hello-kintone-sandbox",
  "version": 1,
  "description": "Sandbox-enabled plugin sample.",
  "homepage": "https://example.com/en/",
  "sandbox": true,
  "allowed_hosts": ["https://example.com", "wss://example.com/ws/*"],
  "permissions": {
    "js_api": ["app:read", "network:connect"],
    "rest_api": ["app_record:read"]
  }
}

plugin upload installation summary — sandbox-aware plugin:

  Installation Summary:
    Destination: https://example.cybozu.com
    File Path: /path/to/plugin.zip
    Plugin ID: <plugin id>
    Plugin Name: hello-kintone-sandbox
    Current version: (not installed)
    Target version: 1
    Sandbox: true
    Allowed hosts: https://example.com, wss://example.com/ws/*
    Permissions (js_api): app:read, network:connect
    Permissions (rest_api): app_record:read

plugin upload installation summary — sandbox-unaware plugin (no extra lines):

  Installation Summary:
    Destination: https://example.cybozu.com
    File Path: /path/to/plugin.zip
    Plugin ID: <plugin id>
    Plugin Name: sample-plugin
    Current version: (not installed)
    Target version: 1

How to test

  • pnpm install
  • pnpm typecheck
  • pnpm test (301 passed / 2 skipped)
  • pnpm lint (ESLint + Prettier)
  • Manual:
    1. plugin pack --input features/assets/plugin_project_sandbox/manifest.json --private-key features/assets/plugin_project_sandbox/private.ppk --output /tmp/plugin.zip
    2. plugin info --input /tmp/plugin.zip (plain / --format json) and confirm the output examples above.
    3. Pack a plugin without any sandbox fields and confirm the sandbox block is omitted in plugin info.

Checklist

  • Read CONTRIBUTING.md
  • Updated documentation if it is required.
  • Added/updated tests if it is required. (or tested manually)
  • Passed pnpm lint and pnpm test on the root directory.

Copilot AI review requested due to automatic review settings April 23, 2026 07:38
@nameless-mc nameless-mc requested a review from a team as a code owner April 23, 2026 07:38
@nameless-mc nameless-mc requested review from chihiro-adachi and shabaraba and removed request for a team April 23, 2026 07:38
@nameless-mc nameless-mc self-assigned this Apr 23, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds CLI support for sandbox-aware plugin manifests by surfacing three new optional manifest fields (sandbox, allowed_hosts, permissions) across plugin pack, plugin info, and plugin upload, along with docs and fixtures/tests.

Changes:

  • Extend manifest types/interfaces (v1 + interface; v2 conformance) to expose sandbox, allowedHosts, and permissions.
  • Update plugin info and plugin upload to conditionally print a cohesive sandbox-related block (plain) and emit manifest-shaped keys (JSON).
  • Add validation fixture + E2E asset/scenarios, plus experimental documentation (EN/JA).

Reviewed changes

Copilot reviewed 20 out of 22 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
website/i18n/ja/docusaurus-plugin-content-docs/current/guide/experimental/sandbox.md Japanese experimental docs for sandbox fields/output
website/docs/guide/experimental/sandbox.md English experimental docs for sandbox fields/output
src/plugin/upload/index.ts Add sandbox summary block to installation summary
src/plugin/info/index.ts Surface sandbox fields in plain + JSON output
src/plugin/core/manifest/v2/index.ts Implement new interface accessors for v2 manifests
src/plugin/core/manifest/v1/index.ts Add v1 accessors + extend v1 JSON type with fields
src/plugin/core/manifest/interface.ts Introduce ManifestPermissions + new accessors
src/plugin/core/manifest/tests/validate.test.ts Add positive validation fixture coverage
src/plugin/core/manifest/tests/fixtures/plugin-sandbox-valid/manifest.json New “valid sandbox manifest” fixture
src/plugin/core/manifest/tests/fixtures/plugin-sandbox-valid/image/icon.png Fixture icon for sandbox-valid manifest
features/plugin/pack.feature E2E scenarios for packing + plugin info output
features/assets/plugin_project_sandbox/private.ppk Test asset private key for sandbox plugin project
features/assets/plugin_project_sandbox/manifest.json Sandbox-aware plugin manifest test asset
features/assets/plugin_project_sandbox/js/mobile.js Sandbox plugin project mobile JS asset
features/assets/plugin_project_sandbox/js/desktop.js Sandbox plugin project desktop JS asset
features/assets/plugin_project_sandbox/js/config.js Sandbox plugin project config JS asset
features/assets/plugin_project_sandbox/image/icon.png Sandbox plugin project icon asset
features/assets/plugin_project_sandbox/html/config.html Sandbox plugin project config HTML asset
features/assets/plugin_project_sandbox/css/mobile.css Sandbox plugin project mobile CSS asset
features/assets/plugin_project_sandbox/css/desktop.css Sandbox plugin project desktop CSS asset
features/assets/plugin_project_sandbox/css/config.css Sandbox plugin project config CSS asset
features/assets/plugin_project_sandbox/css/51-modern-default.css Sandbox plugin project bundled base CSS asset

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread features/assets/plugin_project_sandbox/private.ppk
Comment thread features/assets/plugin_project_sandbox/html/config.html Outdated
Comment thread src/plugin/upload/index.ts Outdated
Comment on lines +44 to +45
"js_api": ["app:read", "network:connect"],
"rest_api": ["app_record:read"]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(将来的に: スコープの種類とか決まったら説明どっかに書くかリンク貼っときたい)

Comment thread src/plugin/info/index.ts Outdated
Comment on lines +31 to +53
const formatList = (list: string[] | undefined) => {
if (list === undefined) {
return "(not set)";
}
if (list.length === 0) {
return "(none)";
}
return list.join(", ");
};

// `permissions.js_api` and `permissions.rest_api` share one parent, so treat
// "parent defined but child absent" as "(none)" rather than "(not set)".
const formatPermissionList = (
list: string[] | undefined,
parentDefined: boolean,
) => {
if (!parentDefined) {
return "(not set)";
}
if (list === undefined || list.length === 0) {
return "(none)";
}
return list.join(", ");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uploadのsummaryと出力内容同じだしまとめてしまっても良さそう

Copy link
Copy Markdown
Contributor Author

@nameless-mc nameless-mc Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

e5978da で対応
出力のスタイルが結構違うのでそこの整形はそれぞれでやってます
(共通化したい)

@nameless-mc nameless-mc force-pushed the feat/plugin-sandbox-fields branch from 8c3522b to e5978da Compare April 27, 2026 03:42
@nameless-mc nameless-mc force-pushed the feat/plugin-sandbox-fields branch from 92115c3 to f5e5ea1 Compare May 11, 2026 08:39
`permissions.js_api` / `permissions.rest_api` are optional arrays in the
manifest schema (validated by @kintone/plugin-manifest-validator), so the
schema distinguishes "child key absent" from "child key declared as empty
array". The previous summary collapsed both into `(none)`, hiding that
distinction in `plugin info` / `plugin upload` output. Align with the
schema: render the absent case as `(not set)` and reserve `(none)` for an
explicitly empty array. Also unify `formatHostList` / `formatPermissionList`
into a single `formatList`.
The sandbox-related lines were appended via `lines.push(...)` after the
array was constructed. Inlining them via a conditional spread keeps the
array a single declarative expression.
The "accessors return raw values; normalization belongs to the validator"
comment was duplicated on both ManifestV1 and ManifestV2. Hoist it to
ManifestInterface so the contract has a single source. The v2 sandbox
getter keeps its own note that v2 does not define a sandbox field.
@nameless-mc nameless-mc force-pushed the feat/plugin-sandbox-fields branch from f5e5ea1 to cb453d6 Compare May 14, 2026 00:44
@nameless-mc nameless-mc force-pushed the feat/plugin-sandbox-fields branch from fab77ac to 052a1d6 Compare May 19, 2026 02:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants