{"id":34178680,"url":"https://github.com/gophercises/secret","last_synced_at":"2026-03-12T03:33:18.676Z","repository":{"id":65385241,"uuid":"133073077","full_name":"gophercises/secret","owner":"gophercises","description":"Ex 17 - Create a Secrets API and CLI","archived":false,"fork":false,"pushed_at":"2020-07-06T15:28:56.000Z","size":10,"stargazers_count":15,"open_issues_count":0,"forks_count":18,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-12-18T10:58:09.644Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://gophercises.com","language":"Go","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/gophercises.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-05-11T18:09:07.000Z","updated_at":"2025-07-08T10:26:45.000Z","dependencies_parsed_at":"2023-01-21T06:45:25.523Z","dependency_job_id":null,"html_url":"https://github.com/gophercises/secret","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/gophercises/secret","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gophercises%2Fsecret","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gophercises%2Fsecret/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gophercises%2Fsecret/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gophercises%2Fsecret/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gophercises","download_url":"https://codeload.github.com/gophercises/secret/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gophercises%2Fsecret/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30414337,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-12T00:40:14.898Z","status":"online","status_checked_at":"2026-03-12T02:00:07.260Z","response_time":114,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":"2025-12-15T13:02:22.138Z","updated_at":"2026-03-12T03:33:18.664Z","avatar_url":"https://github.com/gophercises.png","language":"Go","readme":"# Exercise #17: Secrets CLI \u0026 API\n\n[![exercise status: released](https://img.shields.io/badge/exercise%20status-released-green.svg?style=for-the-badge)](https://gophercises.com/exercises/secret)\n\n## Exercise details\n\nCreate a package that will store secrets - things like API keys - in an encrypted file. Then create a CLI that will make it possible to set and get these secrets via the command line as well.\n\n*The CLI should mostly just be a wrapper around the `secret` package you create that uses a secrets file in your home directory. For more info on creating a CLI or finding the home directory on different OSes see the [task exercise](https://gophercises.com/exercises/task).*\n\nThe way developers use the final version of the `secret` package should look something like this:\n\n```go\nv := secret.FileVault(\"encoding-key\", \"path/to/file\")\nerr := v.Set(\"key-name\", \"key-value\")\nvalue, err := v.Get(\"key-name\")\nfmt.Println(value) // \"key-value\"\n```\n\nFrom the outside the package will look fairly simple, but behind the scenes calling `v.Get` should read and decrypt the file provided and output the value for the provided key. Similarly, `v.Set` should cause your code to open up the file provided, decrypt it, set a new secret key/value pair, then save the file again in an encrypted manner.\n\nCryptography is easy to get wrong, so in the `p1` branch I have provided an `encrypt` package that has both the `Encrypt` and `Decrypt` functions that can be used to encrypt and decrypt strings for you. If you want, feel free to just jump to that branch and copy the code so you don't have to write this particular part of the application.\n\n*The crypto code used in this exercise is based heavily on the code in the standard library's [CFB Encrypter](https://golang.org/pkg/crypto/cipher/#NewCFBEncrypter) and [CFB Decrypter](https://golang.org/pkg/crypto/cipher/#NewCFBDecrypter) examples.*\n\nThe CLI usage should probably end up looking like this:\n\n```bash\n$ secret set twitter_api_key \"some value here\" -k \"your-encoding-key\"\n# Value set!\nsecret get twitter_api_key -k \"your-encoding-key\"\n# \"some value here\"\n```\n\nYou can either provide the key via a flag, or have your program read it via an environment variable. That choice is up to you.\n\n### Readers and Writers\n\nIn the screencasts we also cover how to use the [cipher.StreamReader](https://golang.org/pkg/crypto/cipher/#StreamReader) and [cipher.StreamWriter](https://golang.org/pkg/crypto/cipher/#StreamWriter) which are incredibly cool because they allow us to just wrap any reader and writer with ciphers that will automatically encrypt and decrypt data being written to a writer or read from a reader. This means that the rest of our code doesn't have to even think about the fact that the data in our file is encrypted - it can just use a reader like it normally and with interface chaining we hide that complexity.\n\nIf you code this on your own, I definitely suggest checking out the later videos to see how this all works. Interface chaining is one of the cooler features of Go if you ask me 😀\n\n## Bonus\n\nAdd functionality to list all keys that we have secret values stored for, and add a way to delete a key/value pair.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgophercises%2Fsecret","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgophercises%2Fsecret","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgophercises%2Fsecret/lists"}