├── .github ├── pull_request_template.md ├── submit-button.png └── workflows │ └── validate.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── go.mod ├── go.sum ├── projects.json └── validate.go /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Project name 4 | 5 | #### Short description 6 | 7 | 8 | 9 | #### Project category 10 | 11 | - [ ] Repository 12 | - [ ] Article 13 | - [ ] Video 14 | 15 | #### Developer Tools used 16 | 17 | - [ ] CLI 18 | - [ ] Connect Server 19 | - [ ] CI/CD Integrations 20 | - [ ] SSH Agent 21 | - [ ] Events Reporting API 22 | - [ ] Passage or passwordless 23 | - [ ] SDKs 24 | - [ ] Something else... 25 | 26 | #### URL 27 | 28 | 29 | 30 | #### Author 31 | 32 | 33 | 34 | #### Can we contact you? 35 | 36 | We'd love to be in touch about your project. Would you be open to our Developer Advocates reaching out? 37 | 38 | - [ ] Yes, I'm open. 39 | -------------------------------------------------------------------------------- /.github/submit-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1Password/developer-community-projects/8b4c19ee4122aca4a7ec065492a2d3fcb769aaf5/.github/submit-button.png -------------------------------------------------------------------------------- /.github/workflows/validate.yml: -------------------------------------------------------------------------------- 1 | name: Validate Projects Data 2 | 3 | on: 4 | schedule: 5 | # Every second Monday at 12:00 AM UTC 6 | - cron: '0 0 * * 1/2' 7 | pull_request: 8 | types: 9 | - opened 10 | - synchronize 11 | - reopened 12 | 13 | jobs: 14 | validate: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Check out main branch 18 | uses: actions/checkout@v3 19 | with: 20 | ref: main 21 | 22 | - name: Store projects from main 23 | id: projects-main 24 | run: echo "data=$(cat projects.json | jq -c)" >> $GITHUB_OUTPUT 25 | 26 | - name: Return to PR branch 27 | uses: actions/checkout@v3 28 | 29 | - name: Set up Go 30 | uses: actions/setup-go@v3 31 | with: 32 | go-version: 1.19 33 | 34 | - name: Run validation script 35 | run: go run validate.go 36 | env: 37 | MAIN_PROJECTS_DATA: ${{ steps.projects-main.outputs.data }} 38 | CURRENT_BRANCH: ${{ github.head_ref || github.ref_name }} 39 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribute to Developer Community Projects 2 | 3 | Have you created something using 1Password's Developer Tools? We'd love to hear about it. Open a Pull Request to have your project listed on the [1Password Developer Portal community projects](https://developer.1password.com/community/) page. 4 | 5 | ## What can be submitted? 6 | 7 | We're looking for **repositories** for tools, apps, and other integrations, **articles** or blog posts, or **videos** to help the community. 8 | 9 | If the project is a repository, it should be open source. If it's an article or video, it should be public - no unlisted or paywalled content. 10 | 11 | ℹ️ All submissions are manually reviewed by our team, and we may reject submissions for projects with dubious security practices, that appear to be inflammatory or objectionable, or overwhelmingly don't feel like a valuable contribution to the community. 12 | 13 | ## Steps to submit a project 14 | 15 | 📝 Open a [new Pull Request](https://github.com/1Password/developer-community-projects/compare) using the [default template](https://github.com/1Password/developer-community-projects/blob/main/.github/pull_request_template.md) provided. 16 | 17 | Your PR needs to include an update to the `projects.json` file to add a new object. The new object must adhere to the following criteria: 18 | 19 | - `category` (string) is required, and must be "article", "repo", or "video" 20 | - `id` (string) is required, must be unique, and must only be made up of alphanumeric characters and dashes 21 | - `title` (string) is required 22 | - `author` (string) is required 23 | - `url` (string) is required, must be a URL, and the URL must not redirect 24 | - `description` (string) is optional 25 | - `createdAt` (string) is required, and must be in the format "YYYY-MM-DD" 26 | - `tags` ([]string) is required 27 | 28 | Plaintext strings should not contain URLs, emojis, angle brackets, or any non-printing characters. Please ensure changes match existing code formatting. 29 | 30 | Finally, all commits must be signed. Not signing your commits yet? [We make this easy.](https://developer.1password.com/docs/ssh/git-commit-signing) 31 | 32 | 💬 We're also interested in helping boost projects we love. Let us know in your submission if you're interested in hearing from one of our Developer Advocates! 33 | 34 | ## Other contributions to this repository 35 | 36 | Thanks for your interest in helping improve this repository! While we aren't actively looking for contributions of this nature, we'll still review Pull Requests. 37 | 38 | Please ensure that you adhere to existing code styles and practices, and that your commits are signed. 39 | 40 | ## Code of Conduct 41 | 42 | Reminder: all submissions and interactions are subject to 1Password's [Code of Conduct](https://developer.1password.com/code-of-conduct/) in order to ensure a welcoming and safe space for all. 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 1Password. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

Developer Community Projects

3 |

A collection of projects contributed by the 1Password Developer Community.

4 | 5 | Add your project 6 | 7 |
8 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module developer-community-projects 2 | 3 | go 1.19 4 | 5 | require github.com/go-playground/validator/v10 v10.11.2 6 | 7 | require ( 8 | github.com/go-playground/locales v0.14.1 // indirect 9 | github.com/go-playground/universal-translator v0.18.1 // indirect 10 | github.com/leodido/go-urn v1.2.1 // indirect 11 | golang.org/x/crypto v0.31.0 // indirect 12 | golang.org/x/sys v0.28.0 // indirect 13 | golang.org/x/text v0.21.0 // indirect 14 | ) 15 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 2 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 3 | github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= 4 | github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= 5 | github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= 6 | github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= 7 | github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= 8 | github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= 9 | github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= 10 | github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= 11 | github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= 12 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 13 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 14 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 15 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 16 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 17 | golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= 18 | golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= 19 | golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= 20 | golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 21 | golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= 22 | golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= 23 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 24 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 25 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 26 | -------------------------------------------------------------------------------- /projects.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "category": "repo", 4 | "id": "object-relational-manager-for-1password", 5 | "title": "A ORM implementation for 1Password", 6 | "author": "ilke-dev", 7 | "url": "https://github.com/Ilke-dev/op-orm", 8 | "description": "A Object Relational Manager (ORM) wrapper around the onepassword-sdk-python", 9 | "createdAt": "2025-02-18", 10 | "tags": ["python", "sdk", "orm", "cli", "devops", "automation", "kubernetes", "k8s"] 11 | }, 12 | { 13 | "category": "article", 14 | "id": "sickle-1password-meets-git", 15 | "title": "1Password Meets Git", 16 | "author": "Simon Sickle", 17 | "url": "https://blog.simonsickle.com/1password-meets-git", 18 | "description": "Securing your life in a digital safe deposit box", 19 | "createdAt": "2022-09-15", 20 | "tags": ["git", "ssh"] 21 | }, 22 | { 23 | "category": "article", 24 | "id": "findlay-1password-feature-for-developers", 25 | "title": "The Awesome New 1Password Feature for Developers to Secure and Manage Your Secrets", 26 | "author": "Louise Findlay", 27 | "url": "https://levelup.gitconnected.com/the-awesome-new-1password-feature-for-developers-to-secure-and-manage-your-secrets-b583e47e8693", 28 | "description": "How 1Password secrets automation will help secure, update & sync your developer secrets", 29 | "createdAt": "2022-07-12", 30 | "tags": ["ide", "vs code", "secret reference", "remote"] 31 | }, 32 | { 33 | "category": "article", 34 | "id": "gutmann-ssh-keys-1password", 35 | "title": "SSH key management with 1Password", 36 | "author": "Horst Gutmann", 37 | "url": "https://zerokspot.com/weblog/2022/07/24/ssh-keys-1password/", 38 | "createdAt": "2022-07-24", 39 | "tags": ["ssh"] 40 | }, 41 | { 42 | "category": "article", 43 | "id": "boult-cli-for-secrets", 44 | "title": "Using 1Password CLI for secrets locally", 45 | "author": "Sean Boult", 46 | "url": "https://dev.to/hacksore/using-1password-cli-for-secrets-locally-326e", 47 | "description": "Secrets are the backbone of how developers work in today's data-driven and service world.", 48 | "createdAt": "2022-06-09", 49 | "tags": ["cli", "secret reference", "env"] 50 | }, 51 | { 52 | "category": "article", 53 | "id": "mainwaring-share-local-secrets", 54 | "title": "How to use 1Password to share local secrets", 55 | "author": "Joe Mainwaring", 56 | "url": "https://dev.to/theaccordance/how-to-use-1password-to-share-local-secrets-434d", 57 | "createdAt": "2022-09-22", 58 | "tags": ["cli", "secret reference", "env"] 59 | }, 60 | { 61 | "category": "article", 62 | "id": "belyamani-api-calls-with-ruby", 63 | "title": "Automate GitHub API Calls With Ruby, Keyboard Maestro, and 1Password CLI", 64 | "author": "Moncef Belyamani", 65 | "url": "https://dev.to/monfresh/automate-github-api-calls-with-ruby-keyboard-maestro-and-1password-cli-2ge5", 66 | "createdAt": "2022-09-07", 67 | "tags": ["automation", "ruby", "cli", "github", "keyboard maestro"] 68 | }, 69 | { 70 | "category": "article", 71 | "id": "sanchez-ssh-agent-in-wsl", 72 | "title": "Use 1Password SSH Agent in WSL", 73 | "author": "David Sánchez", 74 | "url": "https://dev.to/d4vsanchez/use-1password-ssh-agent-in-wsl-2j6m", 75 | "description": "You can use 1Password's SSH Agent in WSL, and it's not that complicated.", 76 | "createdAt": "2022-11-06", 77 | "tags": ["ssh", "wsl", "windows"] 78 | }, 79 | { 80 | "category": "article", 81 | "id": "tinkerwell-ssh-agent", 82 | "title": "How to set up the 1Password SSH agent for secure SSH connections", 83 | "author": "Tinkerwell", 84 | "url": "https://tinkerwell.app/blog/how-to-set-up-the-1password-ssh-agent-for-secure-ssh-connections", 85 | "description": "Make sure that no application can grab your private SSH key and share it with someone else who then has access to all your servers.", 86 | "createdAt": "2022-11-25", 87 | "tags": ["ssh"] 88 | }, 89 | { 90 | "category": "article", 91 | "id": "hand-github-ssh-keys-on-windows", 92 | "title": "1Password & Github SSH Keys on Windows", 93 | "author": "Randall Hand", 94 | "url": "https://www.yeraze.com/post/1password-github-ssh-keys-on-windows", 95 | "description": "The most recent version of 1Password from Agilebits had added some great new features, and one I particularly love is SSH Keys.", 96 | "createdAt": "2022-11-25", 97 | "tags": ["ssh", "windows", "github"] 98 | }, 99 | { 100 | "category": "article", 101 | "id": "dellavecchia-authenticate-the-twilio-cli", 102 | "title": "Use Your Fingerprint with 1Password to Authenticate the Twilio CLI", 103 | "author": "Anthony Dellavecchia", 104 | "url": "https://www.twilio.com/en-us/blog/use-your-fingerprint-with-1password-to-authenticate-twilio-cli", 105 | "description": "I'd like to highlight a 1Password Shell Plugin that makes authentication with the Twilio CLI as easy as scanning your fingerprint.", 106 | "createdAt": "2022-12-08", 107 | "tags": ["shell-plugin", "twilio"] 108 | }, 109 | { 110 | "category": "article", 111 | "id": "armstrong-gitlab-cli", 112 | "title": "Put `glab` at your fingertips with the GitLab CLI", 113 | "author": "Kai Armstrong", 114 | "url": "https://about.gitlab.com/blog/2022/12/07/introducing-the-gitlab-cli/", 115 | "description": "We want to integrate GitLab with the tools our developers already use and love.", 116 | "createdAt": "2022-12-07", 117 | "tags": ["shell-plugin", "gitlab"] 118 | }, 119 | { 120 | "category": "repo", 121 | "id": "mrjones2014-op-nvim", 122 | "title": "op.nvim", 123 | "author": "mrjones2014", 124 | "url": "https://github.com/mrjones2014/op.nvim", 125 | "description": "1Password for Neovim! Built using the 1Password CLI, Go, and Lua.", 126 | "createdAt": "2022-07-30", 127 | "tags": ["ide", "cli", "neovim", "lua", "go"] 128 | }, 129 | { 130 | "category": "repo", 131 | "id": "workloads-workspaces", 132 | "title": "workspaces", 133 | "author": "workloads", 134 | "url": "https://github.com/workloads/workspaces", 135 | "description": "Terraform-managed Terraform Cloud (TFC) Workspaces.", 136 | "createdAt":"2022-08-23", 137 | "tags": ["terraform", "hashicorp", "cli"] 138 | }, 139 | { 140 | "category": "repo", 141 | "id": "amadotejada-unopass", 142 | "title": "unopass", 143 | "author": "amadotejada", 144 | "url": "https://github.com/amadotejada/unopass", 145 | "description": "A convenient Python module that allows you to retrieve secrets from the 1Password CLI.", 146 | "createdAt": "2022-06-26", 147 | "tags": ["python", "cli"] 148 | }, 149 | { 150 | "category": "repo", 151 | "id": "twpayne-chezmoi", 152 | "title": "chezmoi", 153 | "author": "twpayne", 154 | "url": "https://github.com/twpayne/chezmoi", 155 | "description": "Manage your dotfiles across multiple diverse machines, securely.", 156 | "createdAt": "2018-10-31", 157 | "tags": ["dotfiles", "cli", "windows", "macos", "linux"] 158 | }, 159 | { 160 | "category": "repo", 161 | "id": "jscarle-onepassword-net", 162 | "title": "OnePassword.NET", 163 | "author": "jscarle", 164 | "url": "https://github.com/jscarle/OnePassword.NET", 165 | "description": "A .NET wrapper for the 1Password command-line tool op.exe.", 166 | "createdAt":"2022-08-21", 167 | "tags": ["csharp", "c#", "cli", "dotnet", ".net"] 168 | }, 169 | { 170 | "category": "repo", 171 | "id": "zcutlip-pyonepassword", 172 | "title": "pyonepassword", 173 | "author": "zcutlip", 174 | "url": "https://github.com/zcutlip/pyonepassword", 175 | "description": "A Python API to query a 1Password account using the 'op' command-line tool.", 176 | "createdAt": "2019-08-07", 177 | "tags": ["python", "cli"] 178 | }, 179 | { 180 | "category": "repo", 181 | "id": "chrisns-kubectl-passman", 182 | "title": "kubectl-passman", 183 | "author": "chrisns", 184 | "url": "https://github.com/chrisns/kubectl-passman", 185 | "description": "kubectl plugin that provides the missing link/glue between common password managers and kubectl.", 186 | "createdAt": "2019-09-23", 187 | "tags": ["kubectl", "cli", "kubernetes", "go"] 188 | }, 189 | { 190 | "category": "repo", 191 | "id": "anasinnyk-terraform-provider-onepassword", 192 | "title": "terraform-provider-onepassword", 193 | "author": "anasinnyk", 194 | "url": "https://github.com/anasinnyk/terraform-provider-onepassword", 195 | "description": "Terraform provider for 1Password.", 196 | "createdAt": "2018-11-27", 197 | "tags": ["terraform", "cli", "go"] 198 | }, 199 | { 200 | "category": "repo", 201 | "id": "tymscar-runelite-1password-plugin", 202 | "title": "runelite-1password-plugin", 203 | "author": "tymscar", 204 | "url": "https://github.com/tymscar/runelite-1password-plugin", 205 | "description": "A plugin that lets you automatically login into your Runescape account in Runelite! ", 206 | "createdAt": "2023-01-05", 207 | "tags": ["runelite", "cli"] 208 | }, 209 | { 210 | "category": "repo", 211 | "id": "yardnsm-tmux-1password", 212 | "title": "tmux-1password", 213 | "author": "yardnsm", 214 | "url": "https://github.com/yardnsm/tmux-1password", 215 | "description": "Access your 1Password login items within tmux!", 216 | "createdAt": "2018-04-24", 217 | "tags": ["tmux", "cli", "jq"] 218 | }, 219 | { 220 | "category": "repo", 221 | "id": "alexanderflink-envop", 222 | "title": "envop", 223 | "author": "alexanderflink", 224 | "url": "https://github.com/alexanderflink/envop", 225 | "description": "A CLI for syncing environment variables using 1Password.", 226 | "createdAt": "2022-08-30", 227 | "tags": ["rust", "cli", "npm"] 228 | }, 229 | { 230 | "category": "repo", 231 | "id": "jjorissen52-env-vault", 232 | "title": "env-vault", 233 | "author": "jjorissen52", 234 | "url": "https://github.com/jjorissen52/env-vault", 235 | "description": "Synchronize your local environment from a secrets vault.", 236 | "createdAt": "2022-04-17", 237 | "tags": ["env", "cli", "npm", "macos", "linux", "typescript"] 238 | }, 239 | { 240 | "category": "repo", 241 | "id": "shyim-idea-1password", 242 | "title": "idea-1password", 243 | "author": "shyim", 244 | "url": "https://github.com/shyim/idea-1password", 245 | "description": "Integrate 1Password into Intellij-based IDEs.", 246 | "createdAt": "2022-08-13", 247 | "tags": ["ide", "cli", "kotlin"] 248 | }, 249 | { 250 | "category": "video", 251 | "id": "hashitalks-bootstrapping-terraform", 252 | "title": "Bootstrapping Terraform Secrets with 1Password CLI", 253 | "author": "HashiCorp", 254 | "url": "https://www.youtube.com/watch?v=fL3QDWJTTOg", 255 | "description": "In this talk, we'll explore how to use 1Password CLI to bootstrap secrets for tools such as Terraform.", 256 | "createdAt": "2022-12-13", 257 | "tags": ["terraform", "hashicorp"] 258 | }, 259 | { 260 | "category": "video", 261 | "id": "gitpod-commit-signing", 262 | "title": "Community Office Hours: Git Signing Commits with 1Password", 263 | "author": "Gitpod", 264 | "url": "https://www.youtube.com/watch?v=u2aCOtMqtc4", 265 | "description": "In this Gitpod Community Office Hours, 1Password Developer Floris van der Grinten talks about using 1Password to sign Git commits", 266 | "createdAt": "2022-11-17", 267 | "tags": ["git", "ssh"] 268 | }, 269 | { 270 | "category": "video", 271 | "id": "short-commit-env-secrets", 272 | "title": "Short: Commit your .env secrets to GitHub", 273 | "author": "Chris Biscardi", 274 | "url": "https://www.youtube.com/shorts/t3pZyyj3OUE", 275 | "description": "In this Short, Chris shows us how to store and access your secrets using secret references.", 276 | "createdAt": "2023-01-07", 277 | "tags": ["secret reference", "env"] 278 | }, 279 | { 280 | "category": "article", 281 | "id": "tratnayake-how-to-securely-work-wth-secrets-during-development", 282 | "title": "How-To Securely Work With Secrets During Development", 283 | "author": "Thilina Ratnayake", 284 | "url": "https://tratnayake.dev/how-to-securely-work-with-secrets-during-development", 285 | "description": "Incorporating the features of enterprise-grade secret management systems into local development processes.", 286 | "createdAt": "2023-02-27", 287 | "tags": ["secret reference", "env", "cli", "dotfiles"] 288 | }, 289 | { 290 | "category": "repo", 291 | "id": "op-connect-sdk-java", 292 | "title": "1Password Connect Java SDK", 293 | "author": "Rohan Nagar", 294 | "url": "https://github.com/RohanNagar/op-connect-sdk-java", 295 | "description": "An unofficial Java SDK for 1Password Connect.", 296 | "createdAt": "2021-04-15", 297 | "tags": ["connect", "java", "sdk", "library"] 298 | }, 299 | { 300 | "category": "article", 301 | "id": "securing-your-homelab-ssh-access-secrets-management-yubikeys-alevski", 302 | "title": "Securing Your Homelab: SSH Access and Secrets Management with 1Password, Yubikeys, and Ansible", 303 | "author": "Lenin Alevski", 304 | "url": "https://www.linkedin.com/pulse/securing-your-homelab-ssh-access-secrets-management-yubikeys-alevski/", 305 | "description": "In this article I show the power of combining 1Password, Yubikeys and ansible for securing SSH access and managing secrets. Although this solution was implemented as a homelab project, it is 100% applicable to startups and small companies.", 306 | "createdAt": "2023-03-28", 307 | "tags": ["automation", "cli", "linux", "secret reference"] 308 | }, 309 | { 310 | "category": "repo", 311 | "id": "1password-alfred-workflow", 312 | "title": "1Password Alfred Workflow", 313 | "author": "Alfred Team", 314 | "url": "https://github.com/alfredapp/1password-workflow/", 315 | "description": "Search and open 1Password items with Alfred", 316 | "createdAt": "2022-04-23", 317 | "tags": ["alfred", "cli", "macos", "search"] 318 | }, 319 | { 320 | "category": "repo", 321 | "id": "lade", 322 | "title": "Lade", 323 | "author": "zifeo", 324 | "url": "https://github.com/zifeo/lade", 325 | "description": "Automatically load secrets from your preferred vault as environment variables, and clear them once your shell command is over.", 326 | "createdAt": "2023-02-01", 327 | "tags": ["cli", "shell", "env"] 328 | }, 329 | { 330 | "category": "repo", 331 | "id": "inserindo-segredos-com-o-1Password", 332 | "title": "Inserindo Segredos com o 1Password", 333 | "author": "guilhermedea", 334 | "url": "https://github.com/guilhermedea/inserindo-segredos-com-o-1Password", 335 | "description": "Guia básico em Português de como inserir segredos no código utilizando o 1Password", 336 | "createdAt": "2023-04-17", 337 | "tags": ["automation", "cli", "visual studio code", "secret reference"] 338 | }, 339 | { 340 | "category": "repo", 341 | "id": "ricardbejarano-go-onepassword", 342 | "title": "1Password Golang SDK", 343 | "author": "Ricard Bejarano", 344 | "url": "https://github.com/ricardbejarano/go-onepassword", 345 | "description": "Access 1Password from Golang code - no Connect server required", 346 | "createdAt": "2023-05-22", 347 | "tags": ["sdk", "go", "library", "cli"] 348 | }, 349 | { 350 | "category": "repo", 351 | "id": "secrets-store-csi-driver-provider-1password", 352 | "title": "1Password Provider for Secret Store CSI Driver", 353 | "author": "meisterlabs", 354 | "url": "https://github.com/MeisterLabs/secrets-store-csi-driver-provider-1password", 355 | "description": "Driver for retreiving 1password secrets using the secrets-store-csi interface for kubernetes, allowing mounting of 1password secrets in kubernetes pods", 356 | "createdAt": "2020-05-13", 357 | "tags": ["automation", "connect", "kubernetes", "go"] 358 | }, 359 | { 360 | "category": "repo", 361 | "id": "mx-rob-git-nidito-joao", 362 | "title": "joão", 363 | "author": "Roberto Hidalgo", 364 | "url": "https://github.com/unRob/joao", 365 | "description": "A command-line configuration manager that keeps entries encoded as YAML in the filesystem, backed up to 1Password; syncs scrubbed copies to git and robots consume entries via 1Password Connect + Vault.", 366 | "createdAt": "2022-11-15", 367 | "tags": ["automation", "cli", "connect", "hashicorp", "vault", "go"] 368 | }, 369 | { 370 | "category": "article", 371 | "id": "cleanup-incorrect-and-duplicates-in-a-1password-account-using-cli", 372 | "title": "Cleaning up incorrect and duplicates in a 1password account using its CLI", 373 | "author": "Saeed Esmaili", 374 | "url": "https://saeedesmaili.com/delete-unwanted-and-duplicated-items-on-1password/", 375 | "description": "A simple guide to clean up a 1Password account by removing incorrect records and duplicates using bash scripting.", 376 | "createdAt": "2023-06-09", 377 | "tags": ["automation", "cli", "mac", "cleanup", "bash"] 378 | }, 379 | { 380 | "category": "article", 381 | "id": "integrate-postman-vault-with-1password", 382 | "title": "Integrate Postman Vault with 1Password", 383 | "author": "Postman", 384 | "url": "https://learning.postman.com/docs/sending-requests/postman-vault/1password/", 385 | "description": "An integration for using 1Password as a secret manager backend with Postman Vault.", 386 | "createdAt": "2024-04-29", 387 | "tags": ["postman", "vault", "service accounts", "secret reference", "1password sdks"] 388 | }, 389 | { 390 | "category": "article", 391 | "id": "1password-support-for-pulumi-esc", 392 | "title": "Announcing 1Password Support for Pulumi ESC in Public Preview", 393 | "author": "Tejitha Raju (Pulumi) and Diana Esteves (Pulumi)", 394 | "url": "https://www.pulumi.com/blog/pulumi-esc-public-preview-for-1password-support/", 395 | "description": "An integration for using 1Password as a secret manager backend with Pulumi ESC.", 396 | "createdAt": "2024-03-27", 397 | "tags": ["pulumi", "esc", "service accounts", "secret reference"] 398 | }, 399 | { 400 | "category": "repo", 401 | "id": "helmfile-vals-1password-support", 402 | "title": "Vals", 403 | "author": "Zois Pagoulatos (zoispag)", 404 | "url": "https://github.com/helmfile/vals?tab=readme-ov-file#1password", 405 | "description": "An integration for using 1Password as a secret backend with vals", 406 | "createdAt": "2024-06-04", 407 | "tags": ["vals", "1password sdks", "secret reference", "service accounts"] 408 | } 409 | ] 410 | -------------------------------------------------------------------------------- /validate.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "net/url" 9 | "os" 10 | "reflect" 11 | "regexp" 12 | "unicode" 13 | 14 | "github.com/go-playground/validator/v10" 15 | ) 16 | 17 | type Project struct { 18 | Category string `json:"category" validate:"required,oneof=article repo video"` 19 | Id string `json:"id" validate:"required,unique_id,alphanumeric_dashes"` 20 | Title string `json:"title" validate:"required,plaintext"` 21 | Author string `json:"author" validate:"required,plaintext"` 22 | Url string `json:"url" validate:"required,url,stable_url"` 23 | Description string `json:"description" validate:"omitempty,plaintext"` 24 | CreatedAt string `json:"createdAt" validate:"required,datetime=2006-01-02"` 25 | Tags []string `json:"tags" validate:"required,dive,plaintext"` 26 | } 27 | 28 | func main() { 29 | var validatedProjects []Project 30 | 31 | currentBranch := getEnvVar("CURRENT_BRANCH") 32 | fmt.Println("Current branch:", currentBranch) 33 | 34 | branchData, err := ioutil.ReadFile("projects.json") 35 | if err != nil { 36 | fmt.Println("Error reading first file:", err) 37 | os.Exit(1) 38 | } 39 | 40 | branchProjects := projectsFromJson(branchData) 41 | 42 | if currentBranch == "main" { 43 | validatedProjects = branchProjects 44 | } else { 45 | mainData := getEnvVar("MAIN_PROJECTS_DATA") 46 | mainProjects := projectsFromJson([]byte(mainData)) 47 | 48 | for i, projectOnCurrentBranch := range branchProjects { 49 | projectUpdated := i < len(mainProjects) && !reflect.DeepEqual(projectOnCurrentBranch, mainProjects[i]) 50 | projectNewlyAdded := i >= len(mainProjects) 51 | 52 | if projectUpdated || projectNewlyAdded { 53 | validatedProjects = append(validatedProjects, projectOnCurrentBranch) 54 | } 55 | } 56 | } 57 | 58 | client := http.Client{ 59 | CheckRedirect: func(req *http.Request, via []*http.Request) error { 60 | return http.ErrUseLastResponse 61 | }, 62 | } 63 | 64 | validationFailed := false 65 | 66 | validate := validator.New() 67 | validate.RegisterValidation("unique_id", UniqueId) 68 | validate.RegisterValidation("alphanumeric_dashes", AlphaNumDashes) 69 | validate.RegisterValidation("plaintext", func(fl validator.FieldLevel) bool { 70 | return PrintOnly(fl) && NoEmojis(fl) && NoUrls(fl) && NoHtmlChars(fl) 71 | }) 72 | validate.RegisterValidation("stable_url", func(fl validator.FieldLevel) bool { 73 | return StableUrl(fl, client) 74 | }) 75 | 76 | validatingJSON, _ := json.MarshalIndent(validatedProjects, "", " ") 77 | fmt.Println("Validating projects:\n", string(validatingJSON)) 78 | 79 | for i, p := range validatedProjects { 80 | err = validate.Struct(p) 81 | if err != nil { 82 | fmt.Printf("Error validating project %d: %s\n", i+1, err) 83 | validationFailed = true 84 | } 85 | } 86 | 87 | if validationFailed { 88 | os.Exit(1) 89 | } else { 90 | os.Exit(0) 91 | } 92 | } 93 | 94 | func projectsFromJson(data []byte) []Project { 95 | var projects []Project 96 | err := json.Unmarshal([]byte(data), &projects) 97 | if err != nil { 98 | fmt.Println("Error unmarshaling data as JSON:", err) 99 | os.Exit(1) 100 | } 101 | 102 | return projects 103 | } 104 | 105 | func getEnvVar(name string) string { 106 | value, ok := os.LookupEnv(name) 107 | if !ok || len(value) == 0 { 108 | fmt.Printf("%s not set\n", name) 109 | os.Exit(1) 110 | } 111 | 112 | return value 113 | } 114 | 115 | var ids = map[string]bool{} 116 | 117 | func UniqueId(fl validator.FieldLevel) bool { 118 | value := fl.Field().String() 119 | if ids[value] { 120 | return false 121 | } 122 | ids[value] = true 123 | return true 124 | } 125 | 126 | func PrintOnly(fl validator.FieldLevel) bool { 127 | for _, r := range fl.Field().String() { 128 | if !unicode.IsPrint(r) { 129 | return false 130 | } 131 | } 132 | 133 | return true 134 | } 135 | 136 | func AlphaNumDashes(fl validator.FieldLevel) bool { 137 | value := fl.Field().String() 138 | match, _ := regexp.MatchString("^[a-zA-Z0-9-]+$", value) 139 | 140 | return match 141 | } 142 | 143 | func NoEmojis(fl validator.FieldLevel) bool { 144 | for _, r := range fl.Field().String() { 145 | if r >= 0x1F600 && r <= 0x1F64F { 146 | return false 147 | } 148 | } 149 | 150 | return true 151 | } 152 | 153 | func NoUrls(fl validator.FieldLevel) bool { 154 | value := fl.Field().String() 155 | re := regexp.MustCompile(`https?://\S+`) 156 | 157 | return !re.MatchString(value) 158 | } 159 | 160 | func NoHtmlChars(fl validator.FieldLevel) bool { 161 | value := fl.Field().String() 162 | // Keeping this pretty loose as it's not uncommon 163 | // for titles to have ampersands and quotes in them, 164 | // and the client is going to encode it anyhow 165 | re := regexp.MustCompile(`[<|>]`) 166 | 167 | return !re.MatchString(value) 168 | } 169 | 170 | func StableUrl(fl validator.FieldLevel, client http.Client) bool { 171 | value := fl.Field().String() 172 | res, err := client.Get(value) 173 | if err != nil { 174 | return false 175 | } 176 | defer res.Body.Close() 177 | 178 | // Medium articles with a custom domain do a redirect through 179 | // medium.com, so this is a special case to allow the 307 180 | if res.StatusCode == 307 { 181 | url, err := url.Parse(res.Header.Get("Location")) 182 | if err != nil { 183 | return false 184 | } 185 | if url.Host == "medium.com" { 186 | return true 187 | } 188 | } 189 | 190 | pass := res.StatusCode == 200 191 | 192 | if !pass { 193 | fmt.Printf("Received status code %d from %s\n", res.StatusCode, value) 194 | } 195 | 196 | return pass 197 | } 198 | --------------------------------------------------------------------------------