{"id":42482614,"url":"https://github.com/cloudspannerecosystem/dynamodb-adapter","last_synced_at":"2026-01-28T11:15:44.191Z","repository":{"id":46035922,"uuid":"267480266","full_name":"cloudspannerecosystem/dynamodb-adapter","owner":"cloudspannerecosystem","description":null,"archived":false,"fork":false,"pushed_at":"2025-11-20T02:04:26.000Z","size":994,"stargazers_count":7,"open_issues_count":22,"forks_count":12,"subscribers_count":9,"default_branch":"master","last_synced_at":"2026-01-17T14:46:39.888Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cloudspannerecosystem.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-05-28T03:05:04.000Z","updated_at":"2025-08-12T17:08:02.000Z","dependencies_parsed_at":"2024-04-19T11:27:56.276Z","dependency_job_id":"2d7f6eb0-d8e1-4dcb-9d28-5e722f913e52","html_url":"https://github.com/cloudspannerecosystem/dynamodb-adapter","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/cloudspannerecosystem/dynamodb-adapter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudspannerecosystem%2Fdynamodb-adapter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudspannerecosystem%2Fdynamodb-adapter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudspannerecosystem%2Fdynamodb-adapter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudspannerecosystem%2Fdynamodb-adapter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cloudspannerecosystem","download_url":"https://codeload.github.com/cloudspannerecosystem/dynamodb-adapter/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudspannerecosystem%2Fdynamodb-adapter/sbom","scorecard":{"id":293279,"data":{"date":"2025-08-11","repo":{"name":"github.com/cloudspannerecosystem/dynamodb-adapter","commit":"97f136a4afbc7fe085c32bb1ba765801bebd9fe2"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.7,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":9,"reason":"Found 23/25 approved changesets -- score normalized to 9","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"1 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: containerImage not pinned by hash: Dockerfile:16","Warn: containerImage not pinned by hash: Dockerfile:39: pin your Docker image by updating debian:bookworm-slim to debian:bookworm-slim@sha256:b1a741487078b369e78119849663d7f1a5341ef2768798f7b7406c4240f86aef","Info:   0 out of   2 containerImage dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 23 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":5,"reason":"5 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GO-2022-0635","Warn: Project is vulnerable to: GO-2022-0646","Warn: Project is vulnerable to: GO-2025-3787 / GHSA-fv92-fjc5-jj9h","Warn: Project is vulnerable to: GO-2022-0355 / GHSA-fx95-883v-4q4h","Warn: Project is vulnerable to: GO-2025-3488 / GHSA-6v2p-p543-phr9"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-17T18:51:28.126Z","repository_id":46035922,"created_at":"2025-08-17T18:51:28.126Z","updated_at":"2025-08-17T18:51:28.126Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28844861,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-28T10:53:21.605Z","status":"ssl_error","status_checked_at":"2026-01-28T10:53:20.789Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-28T11:15:43.455Z","updated_at":"2026-01-28T11:15:44.170Z","avatar_url":"https://github.com/cloudspannerecosystem.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# DynamoDB Adapter\n\n[![Join the chat at\nhttps://gitter.im/cloudspannerecosystem/dynamodb-adapter](https://badges.gitter.im/cloudspannerecosystem/dynamodb-adapter.svg)](https://gitter.im/cloudspannerecosystem/dynamodb-adapter?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n\n[![cloudspannerecosystem](https://circleci.com/gh/cloudspannerecosystem/dynamodb-adapter.svg?style=svg)](https://circleci.com/gh/cloudspannerecosystem/dynamodb-adapter)\n\n## Introduction\n\nDynamoDB Adapter is a tool that translates AWS DynamoDB queries to Cloud\nSpanner equivalent queries and runs those queries on Cloud Spanner. The\nadapter serves as a proxy whereby applications that use DynamoDB can send their\nqueries to the adapter where they are then translated and executed against\nCloud Spanner. DynamoDB Adapter is helpful when moving to Cloud Spanner from\na DynamoDB environment without changing the code for DynamoDB queries. The APIs\ncreated by this project can be directly consumed where DynamoDB queries are\nused in your application.\n\nThe adapter supports the basic data types and operations required for most\napplications.  Additionally, it also supports primary and secondary indexes in\na similar way as DynamoDB. For detailed comparison of supported operations and\ndata types, refer to the [Compatibility Matrix](#compatibility_matrix)\n\n## Examples and Quickstart\n\n**OUTDATED** - The adapter project includes an example application and sample eCommerce\ndata model. The [instructions](./examples/README.md) for the sample\napplication include migration using [Harbourbridge](https://github.com/cloudspannerecosystem/harbourbridge)\nand [setup](./examples/README.md#initialize_the_adapter_configuration) for\nthe adapter.\n\n## Compatibility Matrix\n\n### Supported Actions\n\nDynamoDB Adapter currently supports the following operations:\n\n| DynamoDB Action |\n|----------------|\n| BatchGetItem |\n| BatchWriteItem |\n| DeleteItem |\n| GetItem |\n| PutItem |\n| Query |\n| Scan |\n| UpdateItem |\n| TransactGetItems |\n| TransactWriteItems |\n\n### Supported Data Types\n\nDynamoDB Adapter currently supports the following DynamoDB data types\n\n| DynamoDB Data Type            | Spanner Data Types |\n| ------------------------------| ------------------ |\n| `N` (number type)             | `INT64`, `FLOAT64`, `NUMERIC`, `TIMESTAMP` (EPOCH seconds) |\n| `BOOL` (boolean)              | `BOOL` |\n| `B` (binary type)             | `BYTES(MAX)` |\n| `S` (string and data values)  | `STRING(MAX)` |\n| `SS` (string set)             | `ARRAY\u003cSTRING(MAX)\u003e` |\n| `NS` (number set)             | `ARRAY\u003cFLOAT64\u003e` |\n| `BS` (binary set)             | `ARRAY\u003cBYTES(MAX)\u003e` |\n| `L` (List Type)               | `JSON` |\n| `M` (Map Type)                | `JSON` |\n\nNote: Map and List datatypes does not support the Set datatypes.\n\n## Configuration\n\nThis DynamoDB Adapter requires some initial setup in order to work. There is an initialization section to help bootstrap and create required Spanner tables. Running the init code isn't required but keep in mind that you will have to manually create resources (noted below).\n\n### Auth\n\n#### Spanner Credentials\nThe adapter and initialization both expect GOOGLE_APPLICATION_CREDENTIALS in order to run. On platforms like GCE, GKE, etc., this will be auto picked up at runtime. Locally, make sure to run the following:\n```sh\ngcloud auth application-default login\n```\n\n#### DynamoDB Credentials\nThese can be set either in the `.env` file or by running the following:\n```sh\nexport AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY\nexport AWS_SECRET_ACCESS_KEY=YOUR_SECRET_KEY\nexport AWS_REGION=YOUR_REGION\n```\n\n### config.yaml\n\nThis file defines the necessary settings for the adapter. You should avoid changing this file directly as all fields can be overwritten with env vars. Both the adapters `main.go` and the initilaization's `init.go` will pull in the `config.yaml` file and allow overriding of any value via env vars or a `.env` file.\n\nYou can override `config.yaml` like the following:\n\n`config.yaml`\n```\nspanner:\n  project_id: SPANNER_PROJECT_ID\n```\n\n`.env`\n```\nSPANNER_PROJECT_ID=\u003cyourprojectid\u003e\n```\n\n### .env\n\nThe `.env` file is used to override `config.yaml`. It is not required and you can simply set env vars directly. For deployments on platforms like Docker or GKE, you likely will set env vars specifically for that platform.\n\nCopy the `.env.example` file to `.env` and set needed variables.\n```sh\ncp .env.example .env\n```\n\n### Required Spanner Tables\n\n* `dynamodb_adapter_table_ddl`\n  * Stores the metadata for all DynamoDB tables now\nstored in Cloud Spanner. It is used when the adapter starts up to create a map\nfor all the columns names present in Spanner tables with the columns of tables\npresent in DynamoDB. This mapping is required because DynamoDB supports the\nspecial characters in column names while Cloud Spanner only supports\nunderscores(_). For more: [Spanner Naming Conventions](https://cloud.google.com/spanner/docs/data-definition-language#naming_conventions)\n  * This table also maps DynamoDB types to the underlying Spanner types. This is particularly important for mapping DynamoDB Number to Spanner since there isn't a 1to1 mapping. The adapter will read the Spanner column type and auto-convert reads/writes for that attribute to the closest type to match.\n* `dynamodb_adapter_config_manager`\n\nIf you opt to not use the init code, you can create these tables manually by running:\n```SQL\nCREATE TABLE dynamodb_adapter_table_ddl (\n  column\t     STRING(MAX),\n  tableName      STRING(MAX),\n  dataType       STRING(MAX),\n  originalColumn STRING(MAX),\n) PRIMARY KEY (tableName, column)\n\nCREATE TABLE dynamodb_adapter_config_manager (\n  tableName     STRING(MAX),\n  config \t    STRING(MAX),\n  cronTime      STRING(MAX),\n  enabledStream STRING(MAX),\n  uniqueValue   STRING(MAX),\n) PRIMARY KEY (tableName)\n```\n\n## Initialization\n\nThis repo provides init code to bootstrap the needed resources for the adapter to run. Running this is not required but note that you will have to manually setup required tables. Commands will only run if the resources don't already exist. The init will perform the following:\n\n* Creates new database in Spanner\n* Creates adapter required tables\n  * `dynamodb_adapter_table_ddl`\n  * `dynamodb_adapter_config_manager`\n* Reads from source DynamoDB tables\n* Creates tables in Spanner converting names to match Spanner restrictions\n* Creates table columns converting DynamoDB types to Spanner types on a best effort basis.\n  * Note that by default, all number types are mapped to FLOAT64. You will have to manually adjust the schema for other types.\n* Creates Spanner indexes converting from DynamoDB GSIs and LSIs\n* Inserts rows into the `dynamodb_adapter_table_ddl` table to map DynamoDB -\u003e Spanner attributes\n\nBefore starting, make sure you followed the Configuration setup above. You can ignore any steps calling for manually creating resources.\n\nYou can run the init in dry run mode which will only generate statements instead of creating resources. You can then remove the `--dry_run` flag to actually create needed resources:\n```sh\ngo run config-files/init.go --dry_run\n```\n\n## Starting DynamoDB Adapter\n\nTo start from scratch, complete the steps described in https://cloud.google.com/spanner/docs/getting-started/set-up, which\ncovers creating and setting a default Google Cloud project, enabling billing,\nenabling the Cloud Spanner API, and setting up OAuth 2.0 to get authentication\ncredentials to use the Cloud Spanner API.\n\nEnsure you have already followed the Configuration section notes above.\n\n### Locally or with Binary\nRun directly\n```sh\ngo run main.go\n```\n\nOr\n\nBuild\n```sh\ngo build \\\n  -ldflags \"-X github.com/cloudspannerecosystem/dynamodb-adapter/config.proxyReleaseVersion=$(cat VERSION)\" \\\n  -o dynamodb-adapter\n```\n\nRun Binary\n```sh\n./dynamodb-adapter\n```\n\n### Docker\n\nSet needed env vars (for publishing)\n```\nexport ARTIFACT_REGISTRY_NAME=\"\u003cregistry\u003e\"\nexport ARTIFACT_REGISTRY_PROJECT_ID=\"\u003cproject\u003e\"\nexport ARTIFACT_REGISTRY_REGION=\"\u003cregion\u003e\"\n```\n\nBuild\n```sh\ndocker build \\\n  --platform linux/amd64 \\\n  --build-arg \"PROXY_RELEASE_VERSION=$(cat VERSION)\" \\\n  --tag $ARTIFACT_REGISTRY_REGION-docker.pkg.dev/$ARTIFACT_REGISTRY_PROJECT_ID/$ARTIFACT_REGISTRY_NAME/dynamodb-adapter:$(cat VERSION) .\n```\n\nRunning locally (passes in local GCP creds)\n```sh\ndocker run \\\n  --publish 9050:9050 \\\n  --name dynamodb-adapter \\\n  --detach \\\n  --volume $HOME/.config/gcloud/application_default_credentials.json:/app/application_default_credentials.json:ro \\\n  --env GOOGLE_APPLICATION_CREDENTIALS=/app/application_default_credentials.json \\\n  --env-file .env \\\n  $ARTIFACT_REGISTRY_REGION-docker.pkg.dev/$ARTIFACT_REGISTRY_PROJECT_ID/$ARTIFACT_REGISTRY_NAME/dynamodb-adapter:$(cat VERSION)\n```\n\nPublish\n```sh\ngcloud auth configure-docker $ARTIFACT_REGISTRY_REGION-docker.pkg.dev\ndocker push $ARTIFACT_REGISTRY_REGION-docker.pkg.dev/$ARTIFACT_REGISTRY_PROJECT_ID/$ARTIFACT_REGISTRY_NAME/dynamodb-adapter:$(cat VERSION)\n```\n\n## API Documentation\n\nThis is can be imported in Postman or can be used for Swagger UI.\nYou can get open-api-spec file here [here](https://github.com/cldcvr/dynamodb-adapter/wiki/Open-API-Spec)\n\n## Development\n\n### Unit Tests\n\nRun with \n```sh\ngo test ./... -short \n```\n\n### Integration Tests\n\nThe integrations tests run against a live Spanner instance to perform validations. Integration tests rely on the same `config.yaml` but a local `.env` file if being used.\n\nIf using `.env` files, copy the example to the integrationtest path:\n```sh\ncp .env.example integrationtest/.env\n```\n\n```sh\ncd integrationtest\ngo test . -v\n```\n\nYou can also manually setup/teardown the integration test DB\n```sh\ngo run setup.go setup\ngo run setup.go teardown\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloudspannerecosystem%2Fdynamodb-adapter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcloudspannerecosystem%2Fdynamodb-adapter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloudspannerecosystem%2Fdynamodb-adapter/lists"}