Skip to content

EDSC-4674: Adds NLP and geocoder lambda functions#2053

Open
macrouch wants to merge 4 commits into
mainfrom
EDSC-4674
Open

EDSC-4674: Adds NLP and geocoder lambda functions#2053
macrouch wants to merge 4 commits into
mainfrom
EDSC-4674

Conversation

@macrouch

@macrouch macrouch commented May 29, 2026

Copy link
Copy Markdown
Contributor

Overview

What is the feature?

Adds NLP and geocoder lambda functions

What is the Solution?

The nlpSearch lambda calls Bedrock to parse out the query, then calls various tools to determine the final return value. If spatial was included it will call the geocoder lambda function which will return a spatial bounding box in WKT polygon format

What areas of the application does this impact?

New lambda functions

Testing

In order to get the spatial values you will have to tunnel into CMR OpenSearch

curl -N --location 'http://localhost:3001/nlp?query=rainfall%20in%20Maryland%20south%20of%20Annapolis%20in%202025'

Checklist

  • I have added automated tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings

Summary by CodeRabbit

  • New Features

    • Geocoding: convert natural-language queries into geographic regions
    • NLP search: streamed extraction and analysis of search queries
  • Chores

    • Updated deployment and container build flow; local start scripts now can enable optional services
    • Added local development feature toggles and clearer env guidance
    • Dependency updates and packaging adjustments
  • Documentation

    • README updated with .env/setup guidance and optional services
  • Tests

    • Added tests for NLP extraction behaviors and tools

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 29, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4c74d961-57e4-4637-9d26-4854f82e522c

📥 Commits

Reviewing files that changed from the base of the PR and between a9e0037 and 4efd4ae.

📒 Files selected for processing (2)
  • cdk/earthdata-search/lib/earthdata-search-stack.ts
  • serverless/src/nlpSearch/handler.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • cdk/earthdata-search/lib/earthdata-search-stack.ts
  • serverless/src/nlpSearch/handler.js

📝 Walkthrough

Walkthrough

Adds Bedrock-backed streaming NLP extraction and a Python geocoder Lambda, local feature flags and docs, API proxy streaming support, CDK infra and IAM for Bedrock, build/deploy updates, tests, and dependency/script changes.

Changes

NLP Search & Geocoding Feature

Layer / File(s) Summary
Feature flags and environment configuration
.env.example, .gitignore, README.md
Adds USE_GEOCODER and USE_NLP_SEARCH flags, updates .env.example AWS placeholders to CHANGE-ME, documents .env usage, and ignores local .env.
Package dependencies and npm scripts
package.json
Adds Bedrock SDK and AI deps (@ai-sdk/amazon-bedrock, ai, lambda-stream, zod), test helpers/types, and start scripts (start:geocoder, extended start:optionals).
Local development orchestration
bin/start.js
Refactors optional commands to conditionally include ElasticMQ/SQS and the geocoder process based on USE_GEOCODER, and updates the concurrently invocation.
API proxy streaming support
bin/api.mjs
Adds Node stream helpers, a lightweight awslambda shim for stream responses, normalizes Lambda response bodies to Readable streams, and routes NlpSearchLambdaFunction streaming responses through Fastify with metadata-derived headers.
Build and deploy updates
bin/deploy-bamboo.sh, bin/build-python.sh, geocoder.Dockerfile
Switches to a multi-stage Docker build copying Node tooling into a Python runtime, injects geocoder env vars, adds a Python build script to pip-install geocoder deps, and adds geocoder.Dockerfile.
CDK dependency version alignment
cdk/*/package.json
Bumps/aligns aws-cdk, aws-cdk-lib, and @edsc/cdk-utils versions across CDK packages.
Bedrock IAM permissions
cdk/earthdata-search-infrastructure/lib/earthdata-search-infrastructure-stack.ts
Grants bedrock:InvokeModel and bedrock:InvokeModelWithResponseStream to the EDSCLambdaBase policy.
CDK stack env and bundling
cdk/earthdata-search/lib/earthdata-search-stack.ts
Exposes GEOCODE_INDEX_*, adds USE_GEOCODER/USE_NLP_SEARCH and BEDROCK_MODEL_ID to Lambda environments, and sets bundling depsLockFilePath.
Functions infra: Geocoder & NLP nested stacks
cdk/earthdata-search/lib/earthdata-search-functions.ts
Adds Geocoder nested stack with LogGroup/Lambda/alias/subscription filter, fixes MigrateDatabase bundling path, and provisions nlpSearch nested stack wired to API Gateway STREAM mode.
Geocoder Lambda handler and deps
serverless/src/geocoder/handler.py, serverless/src/geocoder/requirements.txt
New Python main handler that initializes Bedrock LLM and place lookup, optionally downloads S3 cache, returns WKT POLYGON or appropriate HTTP errors; pins Python deps.
NLP Search handler and tools
serverless/src/nlpSearch/handler.js
Streaming handler that uses Bedrock streamText with reportFound, convertTemporal (Zod schema), and lookupSpatial tools; calls local Python geocoder in development or invokes geocoder Lambda in production; exports streamified handler and tool helpers.
NLP Search tests
serverless/src/nlpSearch/__tests__/handler.test.js
Vitest suite that mocks Bedrock streaming and LambdaClient; validates handler streaming messages, final JSON payload, and each tool executor across feature-flag permutations.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant APIGateway as API Proxy
  participant NlpLambda as nlpSearch Lambda
  participant Bedrock
  participant GeocoderLambda

  Client->>APIGateway: GET /nlp?query=...
  APIGateway->>NlpLambda: invoke (streaming)
  NlpLambda->>Bedrock: streamText (tools: reportFound, convertTemporal, lookupSpatial)
  Bedrock-->>NlpLambda: stream progress & tool outputs
  NlpLambda->>GeocoderLambda: Invoke (lookupSpatial) or HTTP dev service
  GeocoderLambda-->>NlpLambda: polygon result
  NlpLambda-->>APIGateway: stream response chunks + final JSON
  APIGateway-->>Client: streamed HTTP response
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 A search now speaks in natural tongue,
From Bedrock's streams the answers sung,
A geocoder hops to map the land,
Node and Python paw in hand,
Feature flags set, local dev is fun!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the primary change—adding NLP and geocoder Lambda functions—which aligns with the main objective of this pull request.
Description check ✅ Passed The PR description covers the required template sections (Overview, Solution, Impact, Testing) with specific details; however, the Checklist items lack supporting evidence (test names, file references) that would typically accompany such claims.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch EDSC-4674

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented May 29, 2026

Copy link
Copy Markdown

Bundle Size Comparison

Full build details

> earthdata-search@1.0.0 build
> vite build

vite v6.4.2 building for production...
transforming...
✓ 4042 modules transformed.
rendering chunks...
computing gzip size...
static/dist/assets/logo-DBK9nthR.webp                                                      0.97 kB
static/dist/assets/logo-CZz0VEVL.webp                                                      1.14 kB
static/dist/assets/logo-Cycj4Zl7.webp                                                      1.33 kB
static/dist/assets/logo-U_2b2F1P.webp                                                      1.37 kB
static/dist/assets/logo-DrQyzv8O.webp                                                      1.54 kB
static/dist/assets/logo-BtXPiD8D.webp                                                      1.81 kB
static/dist/assets/logo-CBoC93bb.webp                                                      2.16 kB
static/dist/assets/logo-DjzD1LMz.webp                                                      2.39 kB
static/dist/assets/orange-bars-circle-D7AglAGM.webp                                        2.77 kB
static/dist/assets/logo-mTUaHBfB.webp                                                      3.11 kB
static/dist/assets/blue-bars-circle-BoIdEwIS.webp                                          3.67 kB
static/dist/assets/logo-BRHnty9h.webp                                                      4.09 kB
static/dist/assets/cryosphere-icon-DSWEvPIt.svg                                            4.11 kB │ gzip:   1.64 kB
static/dist/assets/logo-m8iUFUyE.webp                                                      4.26 kB
static/dist/assets/logo-BI7QOwpp.webp                                                      4.72 kB
static/dist/assets/logo-CjKnSDvE.webp                                                      7.06 kB
static/dist/index.html                                                                    13.22 kB │ gzip:   3.09 kB
static/dist/assets/plate_carree_earth_scaled-RfqGhO39.png                                 18.14 kB
static/dist/assets/tour-video-thumbnail-BxsZeqvq.webp                                     18.84 kB
static/dist/assets/plate_carree_earth_scaled@2x-BIj0Wstc.png                              45.03 kB
static/dist/assets/image-unavailable-CcXgOtQr.svg                                         52.20 kB │ gzip:  20.77 kB
static/dist/assets/earthdata-search-og-image-Cs5RILJ1.webp                                92.82 kB
static/dist/assets/MODIS-Terra-Swirling-Clouds-In-Atlantic-800x600@2x-DdSR_KXb.webp      132.70 kB
static/dist/assets/MODIS-Terra-Swirling-Clouds-In-Atlantic-2560x1440@2x-CZbMhKXi.webp    224.17 kB
static/dist/assets/MODIS-Terra-Swirling-Clouds-In-Atlantic-800x600@2x-DFWWupvf.webp      381.18 kB
static/dist/assets/MODIS-Terra-Swirling-Clouds-In-Atlantic-2560x1440@2x-BwDp59vN.webp    464.37 kB
static/dist/assets/MODIS-Terra-Swirling-Clouds-In-Atlantic-2560x1440@2x-CeYlmMCD.webp    737.44 kB
static/dist/assets/MODIS-Terra-Swirling-Clouds-In-Atlantic-2560x1440@2x-tQ4uTIyn.webp  1,255.87 kB
static/dist/assets/MODIS-Terra-Swirling-Clouds-In-Atlantic-2560x1440@2x-BqbXRJmQ.webp  1,516.81 kB
static/dist/assets/AdminRetrieval-nNSujMnn.css                                             0.06 kB │ gzip:   0.08 kB
static/dist/assets/AdminPreferencesMetrics-GkGryAtC.css                                    0.10 kB │ gzip:   0.11 kB
static/dist/assets/ChunkedOrderModal-DIli9vpQ.css                                          0.11 kB │ gzip:   0.10 kB
static/dist/assets/TooManyPointsModal-D8ufPyjz.css                                         0.14 kB │ gzip:   0.12 kB
static/dist/assets/AdminRetrievalsMetrics-CT7bgXZt.css                                     0.22 kB │ gzip:   0.13 kB
static/dist/assets/AdminPage-D19229XC.css                                                  0.23 kB │ gzip:   0.16 kB
static/dist/assets/ContactInfo-C7Pr11wu.css                                                0.28 kB │ gzip:   0.18 kB
static/dist/assets/useDeleteSubscription-YPccXDF3.css                                      0.46 kB │ gzip:   0.23 kB
static/dist/assets/ShapefileDropzoneContainer-BG7JE7Dj.css                                 0.53 kB │ gzip:   0.26 kB
static/dist/assets/GranuleFiltersContainer-CfwvM6Mp.css                                    0.59 kB │ gzip:   0.27 kB
static/dist/assets/ShapefileUploadModal-CMzmPyoZ.css                                       0.66 kB │ gzip:   0.32 kB
static/dist/assets/Preferences-DGkx-xES.css                                                0.68 kB │ gzip:   0.24 kB
static/dist/assets/Skeleton-DtMOdDsM.css                                                   0.88 kB │ gzip:   0.34 kB
static/dist/assets/TextWindowActions-aNefZur7.css                                          0.91 kB │ gzip:   0.38 kB
static/dist/assets/RelatedCollection-BaShQZdF.css                                          0.93 kB │ gzip:   0.40 kB
static/dist/assets/CollectionDetailsHighlights-CHDYEfjF.css                                1.24 kB │ gzip:   0.44 kB
static/dist/assets/GranuleResultsHighlights-BIY0O9bb.css                                   1.24 kB │ gzip:   0.41 kB
static/dist/assets/Subscriptions-CYrzsucf.css                                              1.26 kB │ gzip:   0.40 kB
static/dist/assets/EDSCModalContainer-D_JXXJBf.css                                         1.77 kB │ gzip:   0.59 kB
static/dist/assets/AdminProjects-CZeT2VXI.css                                              1.98 kB │ gzip:   0.46 kB
static/dist/assets/AdminRetrievals-DIdJ2AD-.css                                            2.02 kB │ gzip:   0.46 kB
static/dist/assets/DownloadHistory-C2TrZbdc.css                                            2.05 kB │ gzip:   0.47 kB
static/dist/assets/DeprecatedParameterModal-nutVvbLm.css                                   2.12 kB │ gzip:   0.93 kB
static/dist/assets/Projects-5m-RoZO0.css                                                   2.13 kB │ gzip:   0.51 kB
static/dist/assets/EchoForm-VVUehB8V.css                                                   3.47 kB │ gzip:   1.06 kB
static/dist/assets/SearchTour-AJompJPK.css                                                 4.82 kB │ gzip:   1.22 kB
static/dist/assets/index-BOElThXL.css                                                      6.47 kB │ gzip:   1.24 kB
static/dist/assets/OrderStatus-qyLNmnfS.css                                                8.49 kB │ gzip:   1.93 kB
static/dist/assets/createSpatialDisplay-CiT4b-tQ.css                                      10.62 kB │ gzip:   2.41 kB
static/dist/assets/MapContainer-GerI1QoD.css                                              17.00 kB │ gzip:   5.89 kB
static/dist/assets/Project-RbLZgqcX.css                                                   20.04 kB │ gzip:   4.07 kB
static/dist/assets/Search-DWJQ45Qd.css                                                    69.43 kB │ gzip:  10.66 kB
static/dist/assets/index-DvsUNaze.css                                                    339.58 kB │ gzip: 109.39 kB
static/dist/assets/logo-BHeuky8i.js                                                        0.06 kB │ gzip:   0.08 kB
static/dist/assets/logo-C2M9lK3U.js                                                        0.06 kB │ gzip:   0.08 kB
static/dist/assets/logo-BbJQ0fWs.js                                                        0.06 kB │ gzip:   0.08 kB
static/dist/assets/logo-CW6PQqmQ.js                                                        0.06 kB │ gzip:   0.08 kB
static/dist/assets/logo-CM8gX-og.js                                                        0.06 kB │ gzip:   0.08 kB
static/dist/assets/logo-CGJHAKVD.js                                                        0.06 kB │ gzip:   0.08 kB
static/dist/assets/logo-DOLER09h.js                                                        0.06 kB │ gzip:   0.08 kB
static/dist/assets/logo-C6Ht_tBx.js                                                        0.06 kB │ gzip:   0.08 kB
static/dist/assets/logo-J7t-4CBp.js                                                        0.06 kB │ gzip:   0.08 kB
static/dist/assets/logo-CxvnVTz2.js                                                        0.06 kB │ gzip:   0.08 kB
static/dist/assets/logo-C9HDQHSy.js                                                        0.06 kB │ gzip:   0.08 kB
static/dist/assets/logo-IHV3gtAZ.js                                                        0.06 kB │ gzip:   0.08 kB
static/dist/assets/logo-Dedvhxzp.js                                                        0.06 kB │ gzip:   0.08 kB
static/dist/assets/logo--kH-hKRS.js                                                        0.06 kB │ gzip:   0.08 kB
static/dist/assets/logo-Z4bYAKVs.js                                                        0.06 kB │ gzip:   0.08 kB
static/dist/assets/logo-nOuRrv94.js                                                        0.06 kB │ gzip:   0.08 kB
static/dist/assets/logo-DIxV4RPX.js                                                        0.06 kB │ gzip:   0.08 kB
static/dist/assets/logo-uABdcgsF.js                                                        0.06 kB │ gzip:   0.08 kB
static/dist/assets/pluralize-49vSaAHF.js                                                   0.08 kB │ gzip:   0.09 kB
static/dist/assets/accessMethodTypes-CY5JnOnd.js                                           0.13 kB │ gzip:   0.14 kB
static/dist/assets/commafy-BfQYQOA4.js                                                     0.14 kB │ gzip:   0.14 kB
static/dist/assets/requestDebounceDuration-B92It3cW.js                                     0.16 kB │ gzip:   0.11 kB
static/dist/assets/subscriptions-DAPgUvgh.js                                               0.41 kB │ gzip:   0.22 kB
static/dist/assets/DownloadsLayout-Cn5tLdmx.js                                             0.44 kB │ gzip:   0.25 kB
static/dist/assets/Table-Cbs46BAa.js                                                       0.60 kB │ gzip:   0.39 kB
static/dist/assets/DefinitionList-CWpE1Syn.js                                              0.63 kB │ gzip:   0.39 kB
static/dist/assets/AdminLayout-CTFovjqh.js                                                 0.63 kB │ gzip:   0.36 kB
static/dist/assets/AdminPage-C-oaGQX4.js                                                   0.68 kB │ gzip:   0.36 kB
static/dist/assets/TooManyPointsModal-DiJuYJjm.js                                          0.74 kB │ gzip:   0.48 kB
static/dist/assets/humanizedQueryValueFormatters-CIZcasg0.js                               1.00 kB │ gzip:   0.54 kB
static/dist/assets/KeyboardShortcutsModal-bBmjQ7Jf.js                                      1.24 kB │ gzip:   0.72 kB
static/dist/assets/metricsDataAccess-B0dv9eSs.js                                           1.26 kB │ gzip:   0.35 kB
static/dist/assets/Skeleton-BhCeSczm.js                                                    1.28 kB │ gzip:   0.58 kB
static/dist/assets/AdminIndex-Cy98n3BB.js                                                  1.36 kB │ gzip:   0.71 kB
static/dist/assets/index-D53X2kvd.js                                                       1.64 kB │ gzip:   0.94 kB
static/dist/assets/AdminProject-BGyrv9-O.js                                                1.68 kB │ gzip:   0.85 kB
static/dist/assets/useLazyQuery-CD8MywGr.js                                                1.70 kB │ gzip:   0.90 kB
static/dist/assets/ShapefileUploadModal-vUZbRtLs.js                                        1.83 kB │ gzip:   0.81 kB
static/dist/assets/DeprecatedParameterModal-CxZTrxwM.js                                    2.07 kB │ gzip:   1.16 kB
static/dist/assets/EditSubscriptionModal-BAw7Fedo.js                                       2.23 kB │ gzip:   1.13 kB
static/dist/assets/EarthdataDownloadRedirect-CGomayuy.js                                   2.24 kB │ gzip:   0.90 kB
static/dist/assets/AboutCSDAModal-BTTRytXG.js                                              2.25 kB │ gzip:   0.99 kB
static/dist/assets/ChunkedOrderModal-Dem_ESwI.js                                           2.34 kB │ gzip:   1.20 kB
static/dist/assets/AdminPreferencesMetrics-cJn3D29T.js                                     2.41 kB │ gzip:   0.84 kB
static/dist/assets/useCreateRetrieval-1vF791cm.js                                          3.31 kB │ gzip:   1.59 kB
static/dist/assets/DownloadHistory-wIfaocUp.js                                             3.41 kB │ gzip:   1.42 kB
static/dist/assets/GranuleResultsHighlights-CQhV5JRk.js                                    3.66 kB │ gzip:   1.35 kB
static/dist/assets/CollectionDetailsHighlights-9y1jS8KO.js                                 3.77 kB │ gzip:   0.99 kB
static/dist/assets/EDSCModalContainer-fYK83AE8.js                                          4.24 kB │ gzip:   1.46 kB
static/dist/assets/AdminRetrieval-0o--v-bb.js                                              4.29 kB │ gzip:   1.78 kB
static/dist/assets/AdminProjects-yOpbT1re.js                                               4.35 kB │ gzip:   1.59 kB
static/dist/assets/Projects-DBoJR3zl.js                                                    4.40 kB │ gzip:   1.72 kB
static/dist/assets/AdminRetrievals-po50qknE.js                                             4.60 kB │ gzip:   1.65 kB
static/dist/assets/AboutCwicModal-p07KB9Cd.js                                              4.69 kB │ gzip:   1.92 kB
static/dist/assets/ContactInfo-rB1KyRKq.js                                                 4.71 kB │ gzip:   1.55 kB
static/dist/assets/Subscriptions-qwGvBinN.js                                               4.79 kB │ gzip:   1.71 kB
static/dist/assets/AdminRetrievalsMetrics-DDy4DNXg.js                                      4.82 kB │ gzip:   1.64 kB
static/dist/assets/useDeleteSubscription-Bk4uWzeE.js                                       6.35 kB │ gzip:   2.44 kB
static/dist/assets/RelatedCollection-CHFDAK4e.js                                          10.41 kB │ gzip:   3.99 kB
static/dist/assets/Modal-xpMhScMY.js                                                      10.74 kB │ gzip:   4.06 kB
static/dist/assets/GranuleFiltersContainer-CaX3A7FI.js                                    21.83 kB │ gzip:   5.91 kB
static/dist/assets/index-CPFHbSMN.js                                                      35.34 kB │ gzip:  12.82 kB
static/dist/assets/styles-BzO8Ie_1.js                                                     60.27 kB │ gzip:  18.66 kB
static/dist/assets/moment-BAtM24Ew.js                                                     60.92 kB │ gzip:  19.77 kB
static/dist/assets/createSpatialDisplay-CJbgDnr4.js                                       60.95 kB │ gzip:  17.01 kB
static/dist/assets/OrderStatus-CKUa-v4Y.js                                                63.29 kB │ gzip:  17.62 kB
static/dist/assets/lodash-DO8XiTt0.js                                                     92.24 kB │ gzip:  31.91 kB
static/dist/assets/EchoForm-DofJm_5t.js                                                  108.53 kB │ gzip:  33.67 kB
static/dist/assets/SearchTour-BY1P5udv.js                                                117.44 kB │ gzip:  35.77 kB
static/dist/assets/ShapefileDropzoneContainer-qiTJATId.js                                119.22 kB │ gzip:  40.01 kB
static/dist/assets/edscUtils-Bp_TfLFE.js                                                 141.73 kB │ gzip:  46.95 kB
static/dist/assets/react-DzPjgnEH.js                                                     230.24 kB │ gzip:  74.44 kB
static/dist/assets/Preferences-jaFXnrfd.js                                               362.19 kB │ gzip: 114.99 kB
static/dist/assets/Project-BidBs3gq.js                                                   398.37 kB │ gzip: 144.04 kB
static/dist/assets/Search-CHSn49Gm.js                                                    493.83 kB │ gzip: 143.98 kB
static/dist/assets/index-BX5JQ8Bm.js                                                   1,025.68 kB │ gzip: 328.97 kB
static/dist/assets/MapContainer-C0GrdqKh.js                                            1,216.27 kB │ gzip: 236.85 kB
✓ built in 36.19s

The full bundle is smaller than main by -849.75 kB. 🎉

The index.js is smaller than main by -103.37 kB. 🎉

Run npx vite-bundle-visualizer to review the bundle in more detail.

File Main Branch Diff
Total 11074.68 kB 10224.93 kB -849.75 kB
index.js 1166.03 kB 1062.66 kB -103.37 kB
index.js (gzip) 363.84 kB 342.73 kB -21.11 kB
index.css 346.05 kB 346.05 kB 0 kB
index.css (gzip) 110.63 kB 110.63 kB 0 kB
Number of files 139 139 0
Build Time 36.33 s 36.19 s -0.14 s

@codecov

codecov Bot commented May 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 86.04651% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 95.77%. Comparing base (9b90045) to head (4efd4ae).

Files with missing lines Patch % Lines
serverless/src/nlpSearch/handler.js 86.04% 11 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2053      +/-   ##
==========================================
- Coverage   95.82%   95.77%   -0.05%     
==========================================
  Files         753      754       +1     
  Lines       17431    17517      +86     
  Branches     4901     4912      +11     
==========================================
+ Hits        16703    16777      +74     
- Misses        677      688      +11     
- Partials       51       52       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 12

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
bin/start.js (1)

70-75: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Keep defaultInputTarget aligned with the optional command count.

Now that optionalCommands can include geocoder, branching only on setupSqs no longer points stdin at the same default process when USE_GEOCODER=true.

Suggested fix
-  defaultInputTarget: setupSqs ? 3 : 1
+  defaultInputTarget: optionalCommands.length + 1
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bin/start.js` around lines 70 - 75, The hardcoded defaultInputTarget
(setupSqs ? 3 : 1) is no longer correct when optionalCommands can include the
geocoder; change it to compute the target from optionalCommands.length so stdin
points to the same logical process regardless of optional commands. Replace the
ternary with an expression like optionalCommands.length + (setupSqs ? 3 : 1)
(adjust the numeric offsets to match your process ordering) so
defaultInputTarget is derived from optionalCommands.length, referencing the
optionalCommands, defaultInputTarget and setupSqs identifiers.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.env.example:
- Around line 16-18: Remove the duplicate AWS_ACCESS_KEY_ID and
AWS_SECRET_ACCESS_KEY entries so only a single pair of credential definitions
remains in the example (keeping the keys named AWS_ACCESS_KEY_ID and
AWS_SECRET_ACCESS_KEY), and convert the note about enabling geocoder/NLP into
commented lines above them so the example does not silently override real values
when copied.

In `@bin/api.mjs`:
- Around line 133-149: The current flow calls reply.send(responseStream) before
applying streaming metadata, so headers/status may be committed too late; change
the sequence in the handler logic to invoke the streaming handler
(handler(event, responseStream, {})) and wait for its returned metadata (or
consult streamMetadataByStream) and apply reply.code(metadata.statusCode) and
reply.headers(metadata.headers) before calling reply.send(responseStream); keep
the Promise.resolve(...).then(...) pattern but move the
reply.send(responseStream) to after the metadata application (and still handle
errors by logging and destroying responseStream in the .catch), referencing the
existing symbols handler, responseStream, streamMetadataByStream, reply.send and
reply.code/reply.headers to locate the code to reorder.

In `@bin/build-python.sh`:
- Around line 3-4: Guard the directory change before running pip: ensure the `cd
serverless/src/geocoder` command cannot fail silently by checking its exit and
aborting if it fails (so `pip install -r requirements.txt -t .` only runs when
the directory change succeeds). Update the script around the `cd
serverless/src/geocoder` and `pip install -r requirements.txt -t .` lines to
either use an explicit conditional check (fail with a clear message and non-zero
exit) or chain with a safe operator so the `pip` invocation never runs on the
wrong working directory.

In `@cdk/earthdata-search/lib/earthdata-search-functions.ts`:
- Line 359: The Lambda request timeout is set to 30s via the property timeout:
cdk.Duration.seconds(30) which is likely too short for cold-start work (S3
download, GeocodeIndexPlaceLookup build, Bedrock extraction); update the timeout
value on the Lambda construct to a higher value (e.g., cdk.Duration.seconds(60)
or cdk.Duration.seconds(120)) or align it with the upstream NLP lambda timeout,
and redeploy so cold-starts don’t cause end-to-end failures.

In `@package.json`:
- Line 30: The "start:geocoder" npm script doesn't pass the AWS region into the
geocoder container; update the docker run for the "start:geocoder" script to
forward the host's region environment variable (e.g., AWS_REGION or
AWS_DEFAULT_REGION) into the container by adding the appropriate -e flag(s) so
the geocoder's Bedrock client can pick up the region (reference the
"start:geocoder" script string in package.json and update the docker run
invocation that runs the geocoder-lambda image).

In `@serverless/src/geocoder/handler.py`:
- Around line 98-99: The temporary INFO-level logging of raw user queries is a
privacy/noise concern; update the logger call in handler.py (the
logger.info(...) that logs the variable query) to either remove it or demote it
to DEBUG (e.g., replace logger.info(f"Received geocoding query: {query}") with
logger.debug(...) or delete the line), and if keeping DEBUG-level logging,
optionally guard with logger.isEnabledFor(logging.DEBUG) to avoid unnecessary
interpolation when debug is off; ensure no raw queries are logged at INFO.

In `@serverless/src/geocoder/requirements.txt`:
- Around line 1-3: Update serverless/src/geocoder/requirements.txt to add a
urllib3 constraint that addresses the CVE by requiring the fixed release line;
specifically add or replace any urllib3 pin with "urllib3>=2.6.3,<3" so
transitive pulls from boto3/botocore (via boto3==1.36.1) will use a patched
urllib3 version and mitigate GHSA-38jv-5279-wg99 / CVE-2026-21441.

In `@serverless/src/nlpSearch/handler.js`:
- Around line 149-160: Remove or redact logging of raw user input and extracted
values: stop writing the raw query to logs (remove or sanitize the
console.log(`Received query: ${query}`) and the responseStream.write('Analyzing
your query...\n') if it exposes the query), and avoid printing the
extractedResults object or its fields (keyword, spatial, spatialArea, temporal);
instead log only non-sensitive status messages or hashed/filtered indicators.
Also remove or change the console.log that prints process.env.USE_NLP_SEARCH
along with any sensitive variables; if you need feature flags keep them but
ensure no user-derived content is included in logs from handler,
responseStream.write, or extractedResults.
- Around line 126-130: lookupSpatialToolExecute currently throws when
process.env.USE_GEOCODER !== 'true', which aborts extraction; change it to
degrade gracefully: remove the throw in lookupSpatialToolExecute and instead
log/warn, skip calling the geocoder, and return without setting spatialArea
(i.e., preserve the incoming spatial value or call setResults with spatialArea
omitted/null) so the rest of the extraction can continue; alternatively ensure
callers omit this tool from the tools list when USE_GEOCODER is false. Reference
symbols: lookupSpatialToolExecute, spatial, setResults,
process.env.USE_GEOCODER.
- Around line 145-148: The handler currently destructures query from
queryStringParameters without checking for its existence; update the handler
function to first verify event.queryStringParameters and that it contains a
non-empty query before destructuring. If missing, write a predictable error
response to responseStream (e.g., a 400 Bad Request JSON message) and return
early; otherwise proceed to extract query and continue normal processing. Ensure
you reference the handler entry point and use responseStream to emit the error
so the function never throws on malformed requests.
- Around line 69-72: The current code assumes every invoke succeeds and directly
returns responsePayload.body; instead validate the Lambda invoke before using
body by checking the invoke result (the response object from
lambdaClient.send(lambdaCommand)) for response.FunctionError or a non-200/202
StatusCode, ensure response.Payload exists, parse it safely into
responsePayload, and verify responsePayload.body is present and valid (e.g.,
non-null and correct type) before returning; if any check fails, throw or return
a descriptive error so the caller (e.g., spatialArea consumer) doesn't receive a
bad value.
- Around line 94-118: The code currently destructures only text from
generateText and then JSON.parse(text); instead, destructure the structured
output from generateText (e.g., const { text, output } = await
generateText(...)) and pass the schema-validated value to setResults('temporal',
output.value) (or output if your generateText returns the value directly) and
update the console.log to use that structured value; remove the JSON.parse(text)
call and rely on Output.object validation instead.

---

Outside diff comments:
In `@bin/start.js`:
- Around line 70-75: The hardcoded defaultInputTarget (setupSqs ? 3 : 1) is no
longer correct when optionalCommands can include the geocoder; change it to
compute the target from optionalCommands.length so stdin points to the same
logical process regardless of optional commands. Replace the ternary with an
expression like optionalCommands.length + (setupSqs ? 3 : 1) (adjust the numeric
offsets to match your process ordering) so defaultInputTarget is derived from
optionalCommands.length, referencing the optionalCommands, defaultInputTarget
and setupSqs identifiers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 48c9c4c7-d73e-45a2-a3df-5ec65d631c27

📥 Commits

Reviewing files that changed from the base of the PR and between 9b90045 and a26cfbf.

⛔ Files ignored due to path filters (4)
  • cdk/earthdata-search-infrastructure/package-lock.json is excluded by !**/package-lock.json
  • cdk/earthdata-search-static/package-lock.json is excluded by !**/package-lock.json
  • cdk/earthdata-search/package-lock.json is excluded by !**/package-lock.json
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (18)
  • .env.example
  • .gitignore
  • bin/api.mjs
  • bin/build-python.sh
  • bin/deploy-bamboo.sh
  • bin/start.js
  • cdk/earthdata-search-infrastructure/lib/earthdata-search-infrastructure-stack.ts
  • cdk/earthdata-search-infrastructure/package.json
  • cdk/earthdata-search-static/package.json
  • cdk/earthdata-search/lib/earthdata-search-functions.ts
  • cdk/earthdata-search/lib/earthdata-search-stack.ts
  • cdk/earthdata-search/package.json
  • geocoder.Dockerfile
  • package.json
  • serverless/src/geocoder/handler.py
  • serverless/src/geocoder/requirements.txt
  • serverless/src/nlpSearch/__tests__/handler.test.js
  • serverless/src/nlpSearch/handler.js

Comment thread .env.example
Comment thread bin/api.mjs
Comment on lines +133 to +149
Promise.resolve(handler(event, responseStream, {}))
.then((streamResponseMetadata) => {
const metadata = streamMetadataByStream.get(responseStream) || streamResponseMetadata || {}

if (metadata?.statusCode) reply.code(metadata.statusCode)
if (metadata?.headers) reply.headers(metadata.headers)

if (metadata?.isBase64Encoded) {
request.log.warn('Streaming response marked as base64 encoded; proxy forwards raw stream chunks.')
}
})
.catch((error) => {
request.log.error({ error }, 'Streaming lambda handler failed')
responseStream.destroy(error)
})

return reply.send(responseStream)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

In Fastify v5, after calling reply.send(stream), can reply.code()orreply.headers() still change the HTTP status code or headers once the stream has started flowing?

💡 Result:

No. Once you call reply.send(stream) and the response has started streaming (i.e., headers have been sent and the payload is flowing), calling reply.code() or reply.headers()/reply.header() will not be able to reliably change the HTTP status code or headers. Fastify’s Reply API is designed such that .code() and .header(s) set status/headers as part of preparing the reply; .send(payload) is the operation that sends the payload. For stream payloads, Fastify treats the stream as “pre-serialized” and “will be sent unmodified”, and .send() is the function that actually sends the payload to the user [1]. Once the stream is being written to the underlying Node http.ServerResponse, Node won’t allow changing status/headers after they’ve already been sent. Practical guidance: set .code() and any .header(s) before reply.send(stream) (or via onSend/other hooks prior to the actual send). Use reply.sent to detect whether reply.send() has already happened [1].

Citations:


Ensure streaming metadata is applied before the response is sent (headers/status must be set pre-stream)

Fastify/Node won’t reliably allow setting HTTP status or headers after the streamed response has started flowing; reply.send(stream) commits headers, and calling reply.code() / reply.headers() later is too late for effect. Since bin/api.mjs applies statusCode/headers only in the .then(...) after reply.send(responseStream), the metadata can fail to take effect if the handler writes the first chunk before the promise resolves.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bin/api.mjs` around lines 133 - 149, The current flow calls
reply.send(responseStream) before applying streaming metadata, so headers/status
may be committed too late; change the sequence in the handler logic to invoke
the streaming handler (handler(event, responseStream, {})) and wait for its
returned metadata (or consult streamMetadataByStream) and apply
reply.code(metadata.statusCode) and reply.headers(metadata.headers) before
calling reply.send(responseStream); keep the Promise.resolve(...).then(...)
pattern but move the reply.send(responseStream) to after the metadata
application (and still handle errors by logging and destroying responseStream in
the .catch), referencing the existing symbols handler, responseStream,
streamMetadataByStream, reply.send and reply.code/reply.headers to locate the
code to reorder.

Comment thread bin/build-python.sh Outdated
role: defaultLambdaConfig.role,
runtime: lambda.Runtime.PYTHON_3_13,
securityGroups: defaultLambdaConfig.securityGroups,
timeout: cdk.Duration.seconds(30),

@coderabbitai coderabbitai Bot May 29, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

30s timeout may be too short for cold-start initialization.

On a cold invocation the handler downloads the place cache from S3, builds GeocodeIndexPlaceLookup (the handler comment notes this is ~15s against OpenSearch when the cache is absent), and then runs the Bedrock extraction — all counted against this 30s request timeout. Since the NLP lambda invokes the geocoder synchronously (5-min timeout), a geocoder timeout fails the whole flow. Consider raising this (e.g. 60–120s) or confirm cold-start latency stays well under 30s.

♻️ Suggested adjustment
-      timeout: cdk.Duration.seconds(30),
+      timeout: cdk.Duration.seconds(60),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
timeout: cdk.Duration.seconds(30),
timeout: cdk.Duration.seconds(60),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cdk/earthdata-search/lib/earthdata-search-functions.ts` at line 359, The
Lambda request timeout is set to 30s via the property timeout:
cdk.Duration.seconds(30) which is likely too short for cold-start work (S3
download, GeocodeIndexPlaceLookup build, Bedrock extraction); update the timeout
value on the Lambda construct to a higher value (e.g., cdk.Duration.seconds(60)
or cdk.Duration.seconds(120)) or align it with the upstream NLP lambda timeout,
and redeploy so cold-starts don’t cause end-to-end failures.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The nlp lambda is invoked through api gateway, so it does have a 30s timeout.

And I've placed the cache file where it needs to be so we don't have that ~15s build time

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@macrouch, thanks for the clarification — both points make sense. API Gateway's ~29s max integration timeout caps the effective execution window anyway, so 30s is exactly right for the geocoder. And with the cache file pre-placed, the expensive GeocodeIndexPlaceLookup build path is bypassed on cold starts. My concern doesn't apply here.

Comment thread package.json
"start:app": "vite dev --port 8080",
"start": "dotenvx run node bin/start.js",
"start:optionals": "USE_IMAGE_CACHE=true SKIP_SQS=false ORDER_DELAY_SECONDS=1 npm start",
"start:geocoder": "docker build -f geocoder.Dockerfile -t geocoder-lambda . && docker run -p 4001:8080 -e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY geocoder-lambda",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Pass the AWS region into the geocoder container.

The local geocoder container only receives access keys right now. That leaves the Bedrock client without a region unless the Dockerfile hardcodes one, which can break the documented local NLP/geocoder flow even when .env is configured correctly.

Suggested fix
-    "start:geocoder": "docker build -f geocoder.Dockerfile -t geocoder-lambda . && docker run -p 4001:8080 -e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY geocoder-lambda",
+    "start:geocoder": "docker build -f geocoder.Dockerfile -t geocoder-lambda . && docker run -p 4001:8080 -e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY -e AWS_REGION=$AWS_REGION -e AWS_DEFAULT_REGION=$AWS_REGION geocoder-lambda",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"start:geocoder": "docker build -f geocoder.Dockerfile -t geocoder-lambda . && docker run -p 4001:8080 -e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY geocoder-lambda",
"start:geocoder": "docker build -f geocoder.Dockerfile -t geocoder-lambda . && docker run -p 4001:8080 -e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY -e AWS_REGION=$AWS_REGION -e AWS_DEFAULT_REGION=$AWS_REGION geocoder-lambda",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@package.json` at line 30, The "start:geocoder" npm script doesn't pass the
AWS region into the geocoder container; update the docker run for the
"start:geocoder" script to forward the host's region environment variable (e.g.,
AWS_REGION or AWS_DEFAULT_REGION) into the container by adding the appropriate
-e flag(s) so the geocoder's Bedrock client can pick up the region (reference
the "start:geocoder" script string in package.json and update the docker run
invocation that runs the geocoder-lambda image).

Comment thread serverless/src/nlpSearch/handler.js
Comment thread serverless/src/nlpSearch/handler.js Outdated
Comment thread serverless/src/nlpSearch/handler.js
Comment thread serverless/src/nlpSearch/handler.js Outdated
Comment thread serverless/src/nlpSearch/handler.js Outdated
Comment on lines +149 to +160
responseStream.write('Analyzing your query...\n')
console.log(`Received query: ${query}`)

const extractedResults = {
keyword: null,
query,
spatial: null,
spatialArea: null,
temporal: null
}

console.log('🚀 ~ handler.js:156 ~ handler ~ process.env.USE_NLP_SEARCH:', process.env.USE_NLP_SEARCH)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid logging raw user queries and extracted values.

Line 150 starts a pattern of writing unredacted search text into logs; the same file also logs raw temporal/spatial inputs and final extracted results. These queries can contain PII or sensitive research intent, so this should be redacted or removed before release.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@serverless/src/nlpSearch/handler.js` around lines 149 - 160, Remove or redact
logging of raw user input and extracted values: stop writing the raw query to
logs (remove or sanitize the console.log(`Received query: ${query}`) and the
responseStream.write('Analyzing your query...\n') if it exposes the query), and
avoid printing the extractedResults object or its fields (keyword, spatial,
spatialArea, temporal); instead log only non-sensitive status messages or
hashed/filtered indicators. Also remove or change the console.log that prints
process.env.USE_NLP_SEARCH along with any sensitive variables; if you need
feature flags keep them but ensure no user-derived content is included in logs
from handler, responseStream.write, or extractedResults.

Comment thread .env.example
Comment thread bin/deploy-bamboo.sh Outdated
functionName: `${functionNamePrefix}-geocoder${defaultLambdaConfig.logGroupSuffix}`,
handler: 'handler.main',
logGroup: geocoderLogGroup,
memorySize: 512,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Check this size

role: defaultLambdaConfig.role,
runtime: lambda.Runtime.PYTHON_3_13,
securityGroups: defaultLambdaConfig.securityGroups,
timeout: cdk.Duration.seconds(30),

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The nlp lambda is invoked through api gateway, so it does have a 30s timeout.

And I've placed the cache file where it needs to be so we don't have that ~15s build time

Comment thread cdk/earthdata-search/lib/earthdata-search-functions.ts Outdated
Comment thread serverless/src/nlpSearch/handler.js Outdated
Comment thread serverless/src/nlpSearch/__tests__/handler.test.js Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
cdk/earthdata-search-infrastructure/lib/earthdata-search-infrastructure-stack.ts (1)

126-132: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Restore least-privilege scoping for Bedrock access.

Changing this statement to Resource: '*' broadens every lambda using EDSCLambdaBase from specific Bedrock model/profile ARNs to all Bedrock resources. That is a real permissions regression for a shared execution role.

Suggested fix
               {
                 Effect: 'Allow',
                 Action: [
                   'bedrock:InvokeModelWithResponseStream',
                   'bedrock:InvokeModel'
                 ],
-                Resource: '*'
+                Resource: [
+                  'arn:aws:bedrock:*::foundation-model/*',
+                  'arn:aws:bedrock:*::inference-profile/*'
+                ]
               }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@cdk/earthdata-search-infrastructure/lib/earthdata-search-infrastructure-stack.ts`
around lines 126 - 132, The IAM statement that grants bedrock:InvokeModel and
bedrock:InvokeModelWithResponseStream is currently using Resource: '*' which
overbroadens every Lambda derived from EDSCLambdaBase; replace the wildcard with
explicit Bedrock model and profile ARNs (or a supplied list of ARNs) so each
role only permits the specific model/profile resources it needs. Locate the
policy attachment in the EDSCLambdaBase-related construct (the statement
containing Action:
['bedrock:InvokeModelWithResponseStream','bedrock:InvokeModel']) and change
Resource from '*' to a scoped array of ARN strings (or hook into a
construct/property that injects allowedModelArns) so the permission is
least-privilege rather than global.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@bin/deploy-bamboo.sh`:
- Line 136: The deploy script currently expands bamboo_BEDROCK_MODEL_ID
unguarded (the -e "BEDROCK_MODEL_ID=$bamboo_BEDROCK_MODEL_ID" environment
argument) which fails under set -u when the Bamboo variable is unset; change the
deploy-bamboo.sh logic to make BEDROCK_MODEL_ID optional by either defaulting
the expansion to an empty string (e.g., use a parameter expansion fallback) or
only append the -e "BEDROCK_MODEL_ID=..." argument when bamboo_BEDROCK_MODEL_ID
is set; update the section that builds the docker run/env list where
BEDROCK_MODEL_ID is added so deployments don't abort when NLP search/Bedrock is
disabled.

In `@serverless/src/nlpSearch/handler.js`:
- Around line 18-19: There is an extra blank line in the nlpSearch handler file
causing the ESLint no-multiple-empty-lines error; open the file and remove the
superfluous empty line so there are no consecutive blank lines (leave at most
one), then save and re-run lint; look around the exported handler
(module.exports or the function named handler) to find and delete the extra
blank line.
- Around line 136-140: The handler currently unconditionally synthesizes a
Washington DC polygon by calling setResults('spatialArea', ...) when
process.env.USE_GEOCODER !== 'true'; remove that synthetic bounding box and
instead do not set spatialArea at all and return/emit a clear response
indicating geocoding is disabled (for example return { ok: false, reason:
'geocoding_disabled' } or set a flag via the existing result API and/or a log
entry). Locate the check using process.env.USE_GEOCODER and the call to
setResults('spatialArea', 'POLYGON(...)') in handler.js and replace the
synthetic setResults call with an explicit non-setting plus a clear disabled
response/log so downstream NLP logic knows geocoding was not performed.

---

Outside diff comments:
In
`@cdk/earthdata-search-infrastructure/lib/earthdata-search-infrastructure-stack.ts`:
- Around line 126-132: The IAM statement that grants bedrock:InvokeModel and
bedrock:InvokeModelWithResponseStream is currently using Resource: '*' which
overbroadens every Lambda derived from EDSCLambdaBase; replace the wildcard with
explicit Bedrock model and profile ARNs (or a supplied list of ARNs) so each
role only permits the specific model/profile resources it needs. Locate the
policy attachment in the EDSCLambdaBase-related construct (the statement
containing Action:
['bedrock:InvokeModelWithResponseStream','bedrock:InvokeModel']) and change
Resource from '*' to a scoped array of ARN strings (or hook into a
construct/property that injects allowedModelArns) so the permission is
least-privilege rather than global.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7e7ebc76-774b-4ab7-9cd4-270217040d1c

📥 Commits

Reviewing files that changed from the base of the PR and between a26cfbf and 6b220d2.

📒 Files selected for processing (12)
  • .env.example
  • README.md
  • bin/build-python.sh
  • bin/deploy-bamboo.sh
  • cdk/earthdata-search-infrastructure/lib/earthdata-search-infrastructure-stack.ts
  • cdk/earthdata-search/lib/earthdata-search-functions.ts
  • cdk/earthdata-search/lib/earthdata-search-stack.ts
  • geocoder.Dockerfile
  • package.json
  • serverless/src/geocoder/requirements.txt
  • serverless/src/nlpSearch/__tests__/handler.test.js
  • serverless/src/nlpSearch/handler.js
💤 Files with no reviewable changes (2)
  • .env.example
  • geocoder.Dockerfile
🚧 Files skipped from review as they are similar to previous changes (5)
  • bin/build-python.sh
  • cdk/earthdata-search/lib/earthdata-search-stack.ts
  • package.json
  • serverless/src/nlpSearch/tests/handler.test.js
  • cdk/earthdata-search/lib/earthdata-search-functions.ts

Comment thread bin/deploy-bamboo.sh
Comment thread serverless/src/nlpSearch/handler.js Outdated
Comment thread serverless/src/nlpSearch/handler.js
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.

1 participant