Explorar o código

feat(access-token-parser): advertise accessTokenHeaderAuth on all token-accepting routes

Add accessTokenHeaderAuth to every apiv3 route security block that already advertises
accessTokenInQuery (26 sites across 9 files, including the features/ai-tools/suggest-path
route initially missed). Drives edits off a full-tree sweep rather than PR #10443's stale
route hunks, absorbing the app-settings path drift and the missing user-activities route.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Yuki Takei hai 2 semanas
pai
achega
6055e85321

+ 8 - 5
.kiro/specs/access-token-parser/design.md

@@ -135,13 +135,16 @@ apps/app/src/server/middlewares/access-token-parser/
 - `apps/app/bin/openapi/definition-apiv1.js` — add `accessTokenHeaderAuth` to
   `components.securitySchemes` and to the top-level `security` array.
 - `apps/app/bin/openapi/definition-apiv3.js` — same as apiv1.
-- The 8 apiv3 route files carrying `accessTokenInQuery` — add `- accessTokenHeaderAuth: []`
-  after every `- accessTokenInQuery: []` block (25 sites total). Authoritative set:
+- The 9 apiv3 route files carrying `accessTokenInQuery` — add `- accessTokenHeaderAuth: []`
+  after every `- accessTokenInQuery: []` block (26 sites total). Authoritative set:
   `activity.ts` (1), `user-activities.ts` (1), `bookmark-folder.ts` (6), `import.ts` (4),
   `in-app-notification.ts` (4), `page-listing.ts` (4), `g2g-transfer.ts` (2),
-  `app-settings/index.ts` (3). **Drift note**: PR #10443 targeted `app-settings.js`
-  (now `app-settings/index.ts`) and omitted `user-activities.ts`; do not apply the PR's
-  route hunks verbatim — drive edits off the current-master `accessTokenInQuery` sites.
+  `app-settings/index.ts` (3), and
+  `features/ai-tools/suggest-path/server/routes/apiv3/index.ts` (1). **Drift note**: PR
+  #10443 targeted `app-settings.js` (now `app-settings/index.ts`), omitted
+  `user-activities.ts`, and predated the `features/` suggest-path route; do not apply the
+  PR's route hunks verbatim — drive edits off a full-tree sweep of current-master
+  `accessTokenInQuery` sites (`grep -rn accessTokenInQuery apps/app/src`).
 
 ## Components and Interfaces
 

+ 13 - 0
.kiro/specs/access-token-parser/research.md

@@ -148,3 +148,16 @@ signatures and all validation/authorization remain unchanged (reuse → R4, R2.2
 **Route-edit method (drift-proof)** — Drive OpenAPI route edits off current-master
 `accessTokenInQuery` sites (8 files / 25 blocks), NOT the PR #10443 file list. Add
 `- accessTokenHeaderAuth: []` after each. Self-check: added line count == 25.
+
+---
+
+## Coverage Correction (task 3.2 implementation)
+
+The gap-analysis route sweep grepped only `apps/app/src/server/routes` and undercounted.
+A full-tree sweep (`grep -rn accessTokenInQuery apps/app/src`) finds **26** sites across
+**9** files — the 8 originally listed plus
+`apps/app/src/features/ai-tools/suggest-path/server/routes/apiv3/index.ts` (1) in the
+`features/` tree. Requirement 5.2 ("every route advertising the query method also
+advertises the header method") requires this 9th file, so task 3.2's scope was extended
+to 26 sites. Lesson: sweep `apps/app/src` (including `features/`), not just
+`server/routes/apiv3`, when enumerating OpenAPI security blocks.

+ 4 - 4
.kiro/specs/access-token-parser/tasks.md

@@ -28,16 +28,16 @@
   - _Boundary: parserForApiToken_
   - _Depends: 1.1_
 
-- [ ] 3. Integration: OpenAPI advertisement of the header method
+- [x] 3. Integration: OpenAPI advertisement of the header method
 - [x] 3.1 (P) Declare the `accessTokenHeaderAuth` security scheme in the apiv1 and apiv3 definitions
   - Add an `apiKey` / `in: header` / `name: x-growi-access-token` scheme to the security schemes and to the top-level security array in both definition files
   - Independent of tasks 2.1/2.2 (separate boundary, no shared files), so it may run concurrently with the parser work
   - Observable: both definition files contain the new scheme while retaining the existing `bearer` and `accessTokenInQuery` schemes
   - _Requirements: 5.1, 5.3_
   - _Boundary: OpenAPI definitions_
-- [ ] 3.2 Apply the header auth method to every advertising route
-  - Add an `accessTokenHeaderAuth` entry after every `accessTokenInQuery` block across the 8 current-master route files (25 sites): activity, user-activities, bookmark-folder, import, in-app-notification, page-listing, g2g-transfer, app-settings index. Do not apply PR #10443's route hunks verbatim — drive edits off the current-master `accessTokenInQuery` sites to absorb the `app-settings` path drift and the missing `user-activities`
-  - Observable: the number of added `accessTokenHeaderAuth` lines equals 25, and every route that advertises `accessTokenInQuery` also advertises `accessTokenHeaderAuth`
+- [x] 3.2 Apply the header auth method to every advertising route
+  - Add an `accessTokenHeaderAuth` entry after every `accessTokenInQuery` block across the 9 current-master route files (26 sites): activity, user-activities, bookmark-folder, import, in-app-notification, page-listing, g2g-transfer, app-settings index, and features/ai-tools/suggest-path. Do not apply PR #10443's route hunks verbatim — drive edits off a full-tree sweep (`grep -rn accessTokenInQuery apps/app/src`) to absorb the `app-settings` path drift, the missing `user-activities`, and the `features/` suggest-path route
+  - Observable: the number of added `accessTokenHeaderAuth` lines equals 26, and every route that advertises `accessTokenInQuery` also advertises `accessTokenHeaderAuth`
   - _Requirements: 5.2_
   - _Boundary: apiv3 route security blocks_
   - _Depends: 3.1_

+ 1 - 0
apps/app/src/features/ai-tools/suggest-path/server/routes/apiv3/index.ts

@@ -99,6 +99,7 @@ const validator = [
  *     security:
  *       - bearer: []
  *       - accessTokenInQuery: []
+ *       - accessTokenHeaderAuth: []
  *     requestBody:
  *       required: true
  *       content:

+ 1 - 0
apps/app/src/server/routes/apiv3/activity.ts

@@ -192,6 +192,7 @@ module.exports = (crowi: Crowi): Router => {
    *     security:
    *       - bearer: []
    *       - accessTokenInQuery: []
+   *       - accessTokenHeaderAuth: []
    *     parameters:
    *       - name: limit
    *         in: query

+ 3 - 0
apps/app/src/server/routes/apiv3/app-settings/index.ts

@@ -392,6 +392,7 @@ module.exports = (crowi: Crowi) => {
    *        security:
    *          - bearer: []
    *          - accessTokenInQuery: []
+   *          - accessTokenHeaderAuth: []
    *        summary: /app-settings
    *        description: get app setting params
    *        responses:
@@ -1087,6 +1088,7 @@ module.exports = (crowi: Crowi) => {
    *        security:
    *          - bearer: []
    *          - accessTokenInQuery: []
+   *          - accessTokenHeaderAuth: []
    *        summary: AccessToken supported.
    *        description: Update V5SchemaMigration
    *        responses:
@@ -1145,6 +1147,7 @@ module.exports = (crowi: Crowi) => {
    *        security:
    *          - bearer: []
    *          - accessTokenInQuery: []
+   *          - accessTokenHeaderAuth: []
    *        summary: AccessToken supported.
    *        description: Update MaintenanceMode
    *        requestBody:

+ 6 - 0
apps/app/src/server/routes/apiv3/bookmark-folder.ts

@@ -150,6 +150,7 @@ module.exports = (crowi: Crowi) => {
    *        security:
    *          - bearer: []
    *          - accessTokenInQuery: []
+   *          - accessTokenHeaderAuth: []
    *        summary: Create bookmark folder
    *        description: Create a new bookmark folder
    *        requestBody:
@@ -215,6 +216,7 @@ module.exports = (crowi: Crowi) => {
    *        security:
    *          - bearer: []
    *          - accessTokenInQuery: []
+   *          - accessTokenHeaderAuth: []
    *        summary: List bookmark folders of a user
    *        description: List bookmark folders of a user
    *        parameters:
@@ -316,6 +318,7 @@ module.exports = (crowi: Crowi) => {
    *        security:
    *          - bearer: []
    *          - accessTokenInQuery: []
+   *          - accessTokenHeaderAuth: []
    *        summary: Delete bookmark folder
    *        description: Delete a bookmark folder and its children
    *        parameters:
@@ -372,6 +375,7 @@ module.exports = (crowi: Crowi) => {
    *        security:
    *          - bearer: []
    *          - accessTokenInQuery: []
+   *          - accessTokenHeaderAuth: []
    *        summary: Update bookmark folder
    *        description: Update a bookmark folder
    *        requestBody:
@@ -437,6 +441,7 @@ module.exports = (crowi: Crowi) => {
    *        security:
    *          - bearer: []
    *          - accessTokenInQuery: []
+   *          - accessTokenHeaderAuth: []
    *        summary: Update bookmark folder
    *        description: Update a bookmark folder
    *        requestBody:
@@ -498,6 +503,7 @@ module.exports = (crowi: Crowi) => {
    *        security:
    *          - bearer: []
    *          - accessTokenInQuery: []
+   *          - accessTokenHeaderAuth: []
    *        summary: Update bookmark in folder
    *        description: Update a bookmark in a folder
    *        requestBody:

+ 2 - 0
apps/app/src/server/routes/apiv3/g2g-transfer.ts

@@ -615,6 +615,7 @@ module.exports = (crowi: Crowi): Router => {
    *      security:
    *        - bearer: []
    *        - accessTokenInQuery: []
+   *        - accessTokenHeaderAuth: []
    *      requestBody:
    *        required: true
    *        content:
@@ -688,6 +689,7 @@ module.exports = (crowi: Crowi): Router => {
    *      security:
    *        - bearer: []
    *        - accessTokenInQuery: []
+   *        - accessTokenHeaderAuth: []
    *      requestBody:
    *        required: true
    *        content:

+ 4 - 0
apps/app/src/server/routes/apiv3/import.ts

@@ -177,6 +177,7 @@ export default function route(crowi: Crowi): Router {
    *      security:
    *        - bearer: []
    *        - accessTokenInQuery: []
+   *        - accessTokenHeaderAuth: []
    *      summary: /import/status
    *      description: Get properties of stored zip files for import
    *      responses:
@@ -213,6 +214,7 @@ export default function route(crowi: Crowi): Router {
    *      security:
    *        - bearer: []
    *        - accessTokenInQuery: []
+   *        - accessTokenHeaderAuth: []
    *      summary: /import
    *      description: import a collection from a zipped json
    *      requestBody:
@@ -375,6 +377,7 @@ export default function route(crowi: Crowi): Router {
    *      security:
    *        - bearer: []
    *        - accessTokenInQuery: []
+   *        - accessTokenHeaderAuth: []
    *      summary: /import/upload
    *      description: upload a zip file
    *      requestBody:
@@ -441,6 +444,7 @@ export default function route(crowi: Crowi): Router {
    *      security:
    *        - bearer: []
    *        - accessTokenInQuery: []
+   *        - accessTokenHeaderAuth: []
    *      summary: /import/all
    *      description: Delete all zip files
    *      responses:

+ 4 - 0
apps/app/src/server/routes/apiv3/in-app-notification.ts

@@ -105,6 +105,7 @@ module.exports = (crowi: Crowi) => {
    *      security:
    *        - bearer: []
    *        - accessTokenInQuery: []
+   *        - accessTokenHeaderAuth: []
    *      summary: /in-app-notification/list
    *      description: Get the list of in-app notifications
    *      parameters:
@@ -207,6 +208,7 @@ module.exports = (crowi: Crowi) => {
    *      security:
    *        - bearer: []
    *        - accessTokenInQuery: []
+   *        - accessTokenHeaderAuth: []
    *      summary: /in-app-notification/status
    *      description: Get the status of in-app notifications
    *      responses:
@@ -250,6 +252,7 @@ module.exports = (crowi: Crowi) => {
    *      security:
    *        - bearer: []
    *        - accessTokenInQuery: []
+   *        - accessTokenHeaderAuth: []
    *      summary: /in-app-notification/open
    *      description: Open the in-app notification
    *      requestBody:
@@ -301,6 +304,7 @@ module.exports = (crowi: Crowi) => {
    *      security:
    *        - bearer: []
    *        - accessTokenInQuery: []
+   *        - accessTokenHeaderAuth: []
    *      summary: /in-app-notification/all-statuses-open
    *      description: Open all in-app notifications
    *      responses:

+ 4 - 0
apps/app/src/server/routes/apiv3/page-listing.ts

@@ -76,6 +76,7 @@ const routerFactory = (crowi: Crowi): Router => {
    *     security:
    *       - bearer: []
    *       - accessTokenInQuery: []
+   *       - accessTokenHeaderAuth: []
    *     summary: /page-listing/root
    *     description: Get the root page
    *     responses:
@@ -113,6 +114,7 @@ const routerFactory = (crowi: Crowi): Router => {
    *     security:
    *       - bearer: []
    *       - accessTokenInQuery: []
+   *       - accessTokenHeaderAuth: []
    *     summary: /page-listing/children
    *     description: Get the children of a page
    *     parameters:
@@ -193,6 +195,7 @@ const routerFactory = (crowi: Crowi): Router => {
    *     security:
    *       - bearer: []
    *       - accessTokenInQuery: []
+   *       - accessTokenHeaderAuth: []
    *     summary: /page-listing/info
    *     description: Get summary information of pages
    *     parameters:
@@ -354,6 +357,7 @@ const routerFactory = (crowi: Crowi): Router => {
    *     security:
    *       - bearer: []
    *       - accessTokenInQuery: []
+   *       - accessTokenHeaderAuth: []
    *     summary: /page-listing/item
    *     description: Get a single page item for tree display
    *     parameters:

+ 1 - 0
apps/app/src/server/routes/apiv3/user-activities.ts

@@ -159,6 +159,7 @@ module.exports = (crowi: Crowi): Router => {
    *       - cookieAuth: []
    *       - bearer: []
    *       - accessTokenInQuery: []
+   *       - accessTokenHeaderAuth: []
    *     parameters:
    *       - name: limit
    *         in: query