{"id":18862798,"url":"https://github.com/eik-lib/sink-gcs","last_synced_at":"2026-02-20T07:02:32.316Z","repository":{"id":36036535,"uuid":"220661371","full_name":"eik-lib/sink-gcs","owner":"eik-lib","description":"Sink for writing and reading files to and from Google Cloud Storage","archived":false,"fork":false,"pushed_at":"2026-02-13T05:59:04.000Z","size":447,"stargazers_count":0,"open_issues_count":4,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-02-13T14:58:31.927Z","etag":null,"topics":["eik","eik-sink"],"latest_commit_sha":null,"homepage":"https://eik.dev","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eik-lib.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":null,"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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2019-11-09T15:21:49.000Z","updated_at":"2026-02-13T05:59:07.000Z","dependencies_parsed_at":"2026-02-06T04:03:37.987Z","dependency_job_id":null,"html_url":"https://github.com/eik-lib/sink-gcs","commit_stats":{"total_commits":351,"total_committers":8,"mean_commits":43.875,"dds":0.4700854700854701,"last_synced_commit":"175cad282c94d9c62d6ed02c9172450717871cf9"},"previous_names":["asset-pipe/sink-gcs"],"tags_count":108,"template":false,"template_full_name":null,"purl":"pkg:github/eik-lib/sink-gcs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eik-lib%2Fsink-gcs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eik-lib%2Fsink-gcs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eik-lib%2Fsink-gcs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eik-lib%2Fsink-gcs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eik-lib","download_url":"https://codeload.github.com/eik-lib/sink-gcs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eik-lib%2Fsink-gcs/sbom","scorecard":{"id":213117,"data":{"date":"2025-08-11","repo":{"name":"github.com/eik-lib/sink-gcs","commit":"342fca9d2057987888c4b3481a56184b6bc65256"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.5,"checks":[{"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":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","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":"Maintained","score":10,"reason":"14 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","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":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: topLevel 'contents' permission set to 'write': .github/workflows/publish.yml:4","Warn: no topLevel permission defined: .github/workflows/test.yml:1","Info: no jobLevel write permissions found"],"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":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish.yml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/eik-lib/sink-gcs/publish.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish.yml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/eik-lib/sink-gcs/publish.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/eik-lib/sink-gcs/test.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/eik-lib/sink-gcs/test.yml/main?enable=pin","Warn: npmCommand not pinned by hash: .github/workflows/publish.yml:28","Warn: npmCommand not pinned by hash: .github/workflows/test.yml:28","Info:   0 out of   4 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   2 npmCommand 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":"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":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"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":"Branch-Protection","score":3,"reason":"branch protection is not maximal on development and all release branches","details":["Info: 'allow deletion' disabled on branch 'main'","Info: 'force pushes' disabled on branch 'main'","Info: 'branch protection settings apply to administrators' is required to merge on branch 'main'","Warn: could not determine whether codeowners review is allowed","Warn: no status checks found to merge onto branch 'main'","Warn: PRs are not required to make changes on branch 'main'; or we don't have data to detect it.If you think it might be the latter, make sure to run Scorecard with a PAT or use Repo Rules (that are always public) instead of Branch Protection settings"],"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":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact v2.0.11 not signed: https://api.github.com/repos/eik-lib/sink-gcs/releases/234357563","Warn: release artifact v2.0.10 not signed: https://api.github.com/repos/eik-lib/sink-gcs/releases/228200344","Warn: release artifact v2.0.9 not signed: https://api.github.com/repos/eik-lib/sink-gcs/releases/225403425","Warn: release artifact v2.0.8 not signed: https://api.github.com/repos/eik-lib/sink-gcs/releases/224759044","Warn: release artifact v2.0.7 not signed: https://api.github.com/repos/eik-lib/sink-gcs/releases/223776371","Warn: release artifact v2.0.11 does not have provenance: https://api.github.com/repos/eik-lib/sink-gcs/releases/234357563","Warn: release artifact v2.0.10 does not have provenance: https://api.github.com/repos/eik-lib/sink-gcs/releases/228200344","Warn: release artifact v2.0.9 does not have provenance: https://api.github.com/repos/eik-lib/sink-gcs/releases/225403425","Warn: release artifact v2.0.8 does not have provenance: https://api.github.com/repos/eik-lib/sink-gcs/releases/224759044","Warn: release artifact v2.0.7 does not have provenance: https://api.github.com/repos/eik-lib/sink-gcs/releases/223776371"],"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":"Packaging","score":10,"reason":"packaging workflow detected","details":["Info: Project packages its releases by way of GitHub Actions.: .github/workflows/publish.yml:18"],"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":"SAST","score":4,"reason":"SAST tool is not run on all commits -- score normalized to 4","details":["Warn: 9 commits out of 20 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"}}]},"last_synced_at":"2025-08-17T01:07:22.693Z","repository_id":36036535,"created_at":"2025-08-17T01:07:22.693Z","updated_at":"2025-08-17T01:07:22.693Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29643961,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-20T05:21:04.652Z","status":"ssl_error","status_checked_at":"2026-02-20T05:21:04.238Z","response_time":59,"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":["eik","eik-sink"],"created_at":"2024-11-08T04:35:45.451Z","updated_at":"2026-02-20T07:02:32.283Z","avatar_url":"https://github.com/eik-lib.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @eik/sink-gcs\n\nA sink for writing to and reading from [Google Cloud Storage][gcs].\n\nThe intention of the [Eik][eik] sink modules is to be able to write to and read from\nfiles in different storage backends by swapping sink modules. Because each sink\nimplements the same public API it is possible to use this sink in one environment and\nanother sink in a different environment.\n\n## Installation\n\n```bash\n$ npm install @eik/sink-gcs\n```\n\n## Example\n\nRead a file from [Google Cloud Storage][gcs] and serve it on HTTP:\n\n```js\nimport { pipeline } from 'node:stream';\nimport express from 'express';\nimport Sink from '@eik/sink-gcs';\n\nconst app = express();\nconst sink = new Sink(\n    {\n        credentials: {\n            client_email: 'a@email.address',\n            private_key: '[ ...snip... ]',\n            projectId: 'myProject',\n        },\n    },\n    {\n        writeTimeout: 20000,\n    },\n);\n\napp.get('/file.js', async (req, res, next) =\u003e {\n    try {\n        const file = await sink.read('/path/to/file/file.js');\n        pipeline(file.stream, res, (error) =\u003e {\n            if (error) return next(error);\n        });\n    } catch (error) {\n        next(error);\n    }\n});\n\napp.listen(8000);\n```\n\n## Constructor\n\nCreate a new Sink instance.\n\n```js\nimport Sink from '@eik/sink-gcs';\n\nconst sink = new Sink({\n    credentials: {\n        client_email: 'a@email.address',\n        private_key: '[ ...snip... ]',\n    },\n    projectId: 'myProject',\n}, {\n    ...options...\n});\n```\n\nThis constructor takes the following arguments:\n\n-   `storageOptions` - Object - A Google Cloud Storage [storage options object][gcs-storage-options] - Required.\n-   `options` - Object - Other options related to storage and behavior - Optional.\n    -   `writeTimeout` - Number - Timeout, in milliseconds, for write operations to the sink - Default: `60000` - Optional.\n    -   `writeGzip` - Boolean - If files should be written with gzip compression - Default: `false` - Optional.\n    -   `rootPath` - String - Root directory for where to store files in the GCS bucket - Default: `eik` - Optional.\n    -   `bucket` - String - Name of the bucket to store files in - Default: `eik_files` - Optional.\n\n## API\n\nThe sink instance has the following API:\n\n### .write(filePath, contentType)\n\nAsync method for writing a file to storage.\n\nThis method takes the following arguments:\n\n-   `filePath` - String - Path to the file to be stored - Required.\n-   `contentType` - String - The content type of the file - Required.\n\nResolves with a writable stream.\n\n```js\nconst { pipeline } = require('stream);\n\nconst fromStream = new SomeReadableStream();\nconst sink = new Sink({ ... });\n\ntry {\n    const file = await sink.write('/path/to/file/file.js', 'application/javascript');\n    pipeline(fromStream, file.stream, (error) =\u003e {\n        if (error) console.log(error);\n    });\n} catch (error) {\n    console.log(error);\n}\n```\n\n### .read(filePath)\n\nAsync method for reading a file from storage.\n\nThis method takes the following arguments:\n\n-   `filePath` - String - Path to the file to be read - Required.\n\nResolves with a [ReadFile][read-file] object which holds metadata about\nthe file and a readable stream with the byte stream of the file on the\n`.stream` property.\n\n```js\nimport { pipeline } from 'node:stream';\n\nconst toStream = new SomeWritableStream();\nconst sink = new Sink({ ... });\n\ntry {\n    const file = await sink.read('/path/to/file/file.js');\n    pipeline(file.stream, toStream, (error) =\u003e {\n        if (error) console.log(error);\n    });\n} catch (error) {\n    console.log(error);\n}\n```\n\n### .delete(filePath)\n\nAsync method for deleting a file in storage.\n\nThis method takes the following arguments:\n\n-   `filePath` - String - Path to the file to be deleted - Required.\n\nResolves if file is deleted and rejects if file could not be deleted.\n\n```js\nconst sink = new Sink({ ... });\n\ntry {\n    await sink.delete('/path/to/file/file.js');\n} catch (error) {\n    console.log(error);\n}\n```\n\n### .exist(filePath)\n\nAsync method for checking if a file exist in the storage.\n\nThis method takes the following arguments:\n\n-   `filePath` - String - Path to the file to be checked for existence - Required.\n\nResolves if file exists and rejects if file does not exist.\n\n```js\nconst sink = new Sink({ ... });\n\ntry {\n    await sink.exist('/path/to/file/file.js');\n} catch (error) {\n    console.log(error);\n}\n```\n\n## Properties\n\nThe Sink instance has the following properties:\n\n### .metrics\n\nAttribute which holds a [metrics stream](https://github.com/metrics-js/client) that\nemits metrics data.\n\nThe stream will emit an event of the following character for each metric:\n\n```js\n{\n    name: 'eik_core_sink_gcs',\n    description: 'Counter measuring access to the Google Cloud Storage sink',\n    timestamp: 1579468682.531,\n    type: 2,\n    value: 1,\n    labels: [\n        {\n            name: 'operation',\n            value: 'write'\n        },\n        {\n            name: 'success',\n            value: true\n        },\n        {\n            name: 'access',\n            value: true\n        }\n    ],\n    time: null,\n    meta: {}\n}\n```\n\nThe metric will have the following labels:\n\n-   `operation` - `String` - The operation which triggered the metric. Can be `write`, `read`, `delete` or `exist`.\n-   `success` - `Boolean` - If the operation was successfull in terms of being a valid operation and running the operation against the Google Cloud Storage without erroring.\n-   `access` - `Boolean` - If the operation triggered access to the Google Cloud Storage.\n\nDo note that the `access` label is `true` when the Sink runs an operation against the\nGoogle Cloud Storage which can generate a cost. In other words; this can be used to\nmonitor excessive access to prevent cost.\n\n## License\n\nCopyright (c) 2020 FINN.no\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n[eik]: https://github.com/eik-lib\n[gcs-auth]: https://googlecloudplatform.github.io/google-cloud-node/#/docs/google-cloud/0.50.0/google-cloud\n[gcs-storage-options]: https://googleapis.dev/nodejs/storage/latest/global.html#StorageOptions\n[gcs]: https://cloud.google.com/storage/\n[read-file]: https://github.com/eik-lib/common/blob/main/lib/classes/read-file.js\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feik-lib%2Fsink-gcs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feik-lib%2Fsink-gcs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feik-lib%2Fsink-gcs/lists"}