@a9n-shoji/rvw 0.15.0 → 0.15.2

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 CHANGED
@@ -5,6 +5,20 @@
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [0.15.2] - 2026-11-02
9
+
10
+ ### Fixed
11
+
12
+ - ウォークスルーへのコメントを `rvw comment get` で取得する際、`assets` が未認識キーとして拒否される不具合を修正しました。
13
+ - 「この依頼に伴う変更を許可」は新規投稿・返信の送信前だけ表示し、投稿後と編集時には表示しないようにしました。
14
+
15
+ ## [0.15.1] - 2026-11-01
16
+
17
+ ### Security
18
+
19
+ - ローカルViewerの画面埋め込みを拒否し、CSPで外部通信とインラインスクリプトなどを制限しました。HTML・Mermaidと同梱画像・フォントの表示は維持しています。
20
+ - HTTP APIのリクエスト本文をJSON解析前に8 MiBへ制限し、コメント参照配列にも200件の上限を適用しました。
21
+
8
22
  ## [0.15.0] - 2026-11-01
9
23
 
10
24
  ### Added
package/dist/cli.mjs CHANGED
@@ -1009,7 +1009,7 @@ function imageContentTypeHeader(contentType2) {
1009
1009
  }
1010
1010
 
1011
1011
  // src/shared/constants.ts
1012
- var APP_VERSION = "0.15.0";
1012
+ var APP_VERSION = "0.15.2";
1013
1013
  var PROTOCOL_VERSION = 7;
1014
1014
  var DEFAULT_VIEWER_PORT = 43117;
1015
1015
  var GIT_OBJECT_ID_PATTERN = /^[0-9a-f]{40,64}$/i;
@@ -1020,6 +1020,7 @@ var MAX_GITHUB_ATTACHMENT_BYTES = 10 * 1024 * 1024;
1020
1020
  var MAX_GITHUB_ATTACHMENT_STDERR_BYTES = 64 * 1024;
1021
1021
  var GITHUB_ATTACHMENT_TIMEOUT_MS = 3e4;
1022
1022
  var MAX_COMMENT_BODY_BYTES = 64 * 1024;
1023
+ var MAX_HTTP_BODY_BYTES = 8 * 1024 * 1024;
1023
1024
  var MAX_AUTHOR_LABEL_CHARACTERS = 100;
1024
1025
  var MAX_IDEMPOTENCY_KEY_CHARACTERS = 200;
1025
1026
  var DEFAULT_PULL_REQUEST_LIST_LIMIT = 50;
@@ -59949,6 +59950,34 @@ var serveStatic = (options = { root: "" }) => {
59949
59950
  };
59950
59951
  };
59951
59952
 
59953
+ // node_modules/.pnpm/hono@4.13.11/node_modules/hono/dist/http-exception.js
59954
+ var HTTPException = class extends Error {
59955
+ res;
59956
+ status;
59957
+ /**
59958
+ * Creates an instance of `HTTPException`.
59959
+ * @param status - HTTP status code for the exception. Defaults to 500.
59960
+ * @param options - Additional options for the exception.
59961
+ */
59962
+ constructor(status = 500, options) {
59963
+ super(options?.message, { cause: options?.cause });
59964
+ this.res = options?.res;
59965
+ this.status = status;
59966
+ }
59967
+ /**
59968
+ * Returns the response object associated with the exception.
59969
+ * If a response object is not provided, a new response is created with the error message and status code.
59970
+ * @returns The response object.
59971
+ */
59972
+ getResponse() {
59973
+ if (this.res) return new Response(this.res.body, {
59974
+ status: this.status,
59975
+ headers: this.res.headers
59976
+ });
59977
+ return new Response(this.message, { status: this.status });
59978
+ }
59979
+ };
59980
+
59952
59981
  // node_modules/.pnpm/hono@4.13.11/node_modules/hono/dist/request/constants.js
59953
59982
  var GET_MATCH_RESULT = /* @__PURE__ */ Symbol();
59954
59983
 
@@ -61719,6 +61748,40 @@ var Hono3 = class extends Hono {
61719
61748
  }
61720
61749
  };
61721
61750
 
61751
+ // node_modules/.pnpm/hono@4.13.11/node_modules/hono/dist/middleware/body-limit/index.js
61752
+ var ERROR_MESSAGE = "Payload Too Large";
61753
+ var bodyLimit = (options) => {
61754
+ const onError = options.onError || (() => {
61755
+ const res = new Response(ERROR_MESSAGE, { status: 413 });
61756
+ throw new HTTPException(413, { res });
61757
+ });
61758
+ const maxSize = options.maxSize;
61759
+ return async function bodyLimit2(c, next2) {
61760
+ if (!c.req.raw.body) return next2();
61761
+ const hasTransferEncoding = c.req.raw.headers.has("transfer-encoding");
61762
+ if (c.req.raw.headers.has("content-length") && !hasTransferEncoding) return parseInt(c.req.raw.headers.get("content-length") || "0", 10) > maxSize ? onError(c) : next2();
61763
+ let size = 0;
61764
+ const chunks = [];
61765
+ const rawReader = c.req.raw.body.getReader();
61766
+ for (; ; ) {
61767
+ const { done, value } = await rawReader.read();
61768
+ if (done) break;
61769
+ size += value.length;
61770
+ if (size > maxSize) return onError(c);
61771
+ chunks.push(value);
61772
+ }
61773
+ const requestInit = {
61774
+ body: new ReadableStream({ start(controller) {
61775
+ for (const chunk of chunks) controller.enqueue(chunk);
61776
+ controller.close();
61777
+ } }),
61778
+ duplex: "half"
61779
+ };
61780
+ c.req.raw = new Request(c.req.raw, requestInit);
61781
+ return next2();
61782
+ };
61783
+ };
61784
+
61722
61785
  // src/application/agent-command-schemas.ts
61723
61786
  var nonEmptyString = external_exports.string().min(1);
61724
61787
  var commentUri = external_exports.string().regex(/^rvw:\/\/comment\//);
@@ -62180,7 +62243,7 @@ var createCommentSchema = external_exports.object({
62180
62243
  body: external_exports.string().min(1).refine((value) => Buffer.byteLength(value, "utf8") <= MAX_COMMENT_BODY_BYTES),
62181
62244
  authorLabel: external_exports.string().max(MAX_AUTHOR_LABEL_CHARACTERS).nullable().optional(),
62182
62245
  relatedCommitOid: external_exports.string().regex(GIT_OBJECT_ID_PATTERN).nullable().optional(),
62183
- references: external_exports.array(codeReferenceInputSchema).optional()
62246
+ references: external_exports.array(codeReferenceInputSchema).max(MAX_CODE_REFERENCES).optional()
62184
62247
  }).superRefine((input2, context) => {
62185
62248
  if ((input2.references?.length ?? 0) > 0 && !input2.relatedCommitOid) {
62186
62249
  context.addIssue({
@@ -62195,7 +62258,7 @@ var replySchema = external_exports.object({
62195
62258
  body: external_exports.string().min(1).refine((value) => Buffer.byteLength(value, "utf8") <= MAX_COMMENT_BODY_BYTES),
62196
62259
  relatedCommitOid: external_exports.string().regex(GIT_OBJECT_ID_PATTERN).nullable().optional(),
62197
62260
  authorLabel: external_exports.string().max(MAX_AUTHOR_LABEL_CHARACTERS).nullable().optional(),
62198
- references: external_exports.array(codeReferenceInputSchema).optional()
62261
+ references: external_exports.array(codeReferenceInputSchema).max(MAX_CODE_REFERENCES).optional()
62199
62262
  }).superRefine((input2, context) => {
62200
62263
  if ((input2.references?.length ?? 0) > 0 && !input2.relatedCommitOid) {
62201
62264
  context.addIssue({
@@ -62207,7 +62270,7 @@ var replySchema = external_exports.object({
62207
62270
  });
62208
62271
  var editCommentPostSchema = external_exports.object({
62209
62272
  body: external_exports.string().min(1).refine((value) => Buffer.byteLength(value, "utf8") <= MAX_COMMENT_BODY_BYTES),
62210
- references: external_exports.array(codeReferenceInputSchema).optional()
62273
+ references: external_exports.array(codeReferenceInputSchema).max(MAX_CODE_REFERENCES).optional()
62211
62274
  });
62212
62275
  var placementDocumentRefSchema = external_exports.discriminatedUnion("kind", [
62213
62276
  external_exports.object({ kind: external_exports.literal("pull-request-markdown"), pullRequestId: external_exports.uuid() }),
@@ -62235,6 +62298,29 @@ var resolveCodeReferencePlacementSchema = external_exports.object({
62235
62298
  reference: codeReferenceInputSchema
62236
62299
  });
62237
62300
 
62301
+ // src/server/security-headers.ts
62302
+ var viewerContentSecurityPolicy = [
62303
+ "default-src 'none'",
62304
+ "script-src 'self'",
62305
+ "style-src 'self' 'unsafe-inline'",
62306
+ "img-src 'self' data: blob:",
62307
+ "font-src 'self' data:",
62308
+ "connect-src 'self'",
62309
+ "frame-src 'self'",
62310
+ "worker-src 'none'",
62311
+ "object-src 'none'",
62312
+ "base-uri 'none'",
62313
+ "form-action 'none'",
62314
+ "frame-ancestors 'none'"
62315
+ ].join("; ");
62316
+ var securityHeaders = async (context, next2) => {
62317
+ context.header("Content-Security-Policy", viewerContentSecurityPolicy);
62318
+ context.header("X-Frame-Options", "DENY");
62319
+ context.header("X-Content-Type-Options", "nosniff");
62320
+ context.header("Referrer-Policy", "no-referrer");
62321
+ await next2();
62322
+ };
62323
+
62238
62324
  // src/server/app.ts
62239
62325
  var oidSchema = external_exports.string().regex(GIT_OBJECT_ID_PATTERN);
62240
62326
  var contentFingerprintSchema = external_exports.string().regex(CONTENT_FINGERPRINT_PATTERN);
@@ -62317,6 +62403,7 @@ function documentRefFromQuery(pullRequestId, query) {
62317
62403
  }
62318
62404
  function createApp(service, options) {
62319
62405
  const app = new Hono3();
62406
+ app.use("*", securityHeaders);
62320
62407
  app.use("*", async (context, next2) => {
62321
62408
  const expectedHost = options.security.expectedHost;
62322
62409
  if (!expectedHost || context.req.header("host") !== expectedHost) {
@@ -62340,6 +62427,17 @@ function createApp(service, options) {
62340
62427
  }
62341
62428
  await next2();
62342
62429
  });
62430
+ app.use(
62431
+ "/api/*",
62432
+ bodyLimit({
62433
+ maxSize: MAX_HTTP_BODY_BYTES,
62434
+ onError: () => {
62435
+ throw new RvwError("INVALID_INPUT", "HTTP request body\u306F8 MiB\u4EE5\u4E0B\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002", {
62436
+ status: 413
62437
+ });
62438
+ }
62439
+ })
62440
+ );
62343
62441
  app.onError((error62, context) => {
62344
62442
  const rvwError = error62 instanceof external_exports.ZodError ? new RvwError("INVALID_INPUT", "request\u304CAPI schema\u306B\u9069\u5408\u3057\u307E\u305B\u3093\u3002", {
62345
62443
  details: external_exports.treeifyError(error62)
@@ -64223,6 +64321,14 @@ var reviewCommentOutputSchema = external_exports.object({
64223
64321
  posts: external_exports.array(commentPostOutputSchema)
64224
64322
  }).strict();
64225
64323
  var walkthroughOutputSchema = external_exports.object({
64324
+ assets: external_exports.array(
64325
+ external_exports.object({
64326
+ path: external_exports.string(),
64327
+ mediaType: external_exports.string(),
64328
+ byteLength: external_exports.number().int().min(0),
64329
+ sha256: external_exports.string()
64330
+ }).strict()
64331
+ ).optional(),
64226
64332
  id: external_exports.string(),
64227
64333
  ref: external_exports.string(),
64228
64334
  pullRequestId: external_exports.string(),