{"id":19293952,"url":"https://github.com/igrishaev/mask","last_synced_at":"2025-04-22T07:32:31.251Z","repository":{"id":107212087,"uuid":"606418227","full_name":"igrishaev/mask","owner":"igrishaev","description":null,"archived":false,"fork":false,"pushed_at":"2023-03-08T08:18:05.000Z","size":25,"stargazers_count":12,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-01T20:51:24.762Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/igrishaev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"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":"2023-02-25T12:40:09.000Z","updated_at":"2024-11-10T18:38:45.000Z","dependencies_parsed_at":"2023-03-09T02:30:42.301Z","dependency_job_id":null,"html_url":"https://github.com/igrishaev/mask","commit_stats":{"total_commits":13,"total_committers":1,"mean_commits":13.0,"dds":0.0,"last_synced_commit":"d1af74c79c6333a87ae3d90720df6a67d0bf7cd1"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igrishaev%2Fmask","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igrishaev%2Fmask/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igrishaev%2Fmask/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igrishaev%2Fmask/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/igrishaev","download_url":"https://codeload.github.com/igrishaev/mask/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250195054,"owners_count":21390230,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":"2024-11-09T22:36:40.116Z","updated_at":"2025-04-22T07:32:31.244Z","avatar_url":"https://github.com/igrishaev.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Mask\n\nA small library to prevent secrets from being logged, printed or leaked in any\nsimilar way. Ships tags for Clojure, EDN and Aero.\n\nWhy? Because I've been in such a situation three times, namely:\n\n- We don't mask the secrets.\n- Someone logs the entire config.\n- Secrets have leaked!\n- Rotate all the keys, tokens, etc.\n- Change the team and face the same.\n\nThis library is an attempt to break this vicious circle.\n\n## Installation\n\nLeiningen/Boot:\n\n```clojure\n[com.github.igrishaev/mask \"0.1.1\"]\n```\n\nClojure CLI/deps.edn:\n\n```clojure\ncom.github.igrishaev/mask {:mvn/version \"0.1.1\"}\n```\n\n## Usage\n\nThe `mask.core` namespace provides `mask` and `unmask` functions. Pass a value\nto `mask` to make it safe for logging or printing in REPL:\n\n```clojure\n(in-ns 'mask.core)\n#namespace[mask.core]\n\n(def -m (mask \"Secret123\"))\n\n-m\n\u003c\u003c masked \u003e\u003e\n\n(str \"The password is \" -m)\n\"The password is \u003c\u003c masked \u003e\u003e\"\n```\n\nMasking is idempotent meaning that you can mask the same value multiple times\nbut the result will be one-level masked value:\n\n```clojure\n(-\u003e -m mask mask mask)\n\u003c\u003c masked \u003e\u003e\n```\n\nTo release a value from a mask, `unmask` it:\n\n```clojure\n(unmask -m)\n\"Secret123\"\n```\n\nUnmasking is idempotent a well:\n\n```\n(-\u003e -m unmask unmask unmask)\n\"Secret123\"\n```\n\nNote: the library treats `nil` as an error value that cannot be masked. You'll\nget an exception:\n\n```clojure\n(mask nil)\nExecution error (IllegalArgumentException) at ... (core.clj:34).\nCannot mask a nil value\n```\n\nMasking an empty value signals you're doing something wrong. Most likely you've\nmissed a corresponding key or an environment variable. Thus, the further work\nmakes no sense.\n\n### Spec\n\nThe `mask.spec` module provides the `::mask` spec that checks if a value is\nreally masked. An example from the tests:\n\n```clojure\n(let [config\n      {:username \"Ivan\"\n       :password #mask \"secret\"}]\n\n  (is (s/valid? ::config config)))\n\n;; true\n```\n\n### Clojure tags\n\nThe built-in `#mask` tag wraps any value with a mask:\n\n```clojure\n=\u003e {:token #mask \"abc123\" :password \"SecretABC\"}\n\n{:token \u003c\u003c masked \u003e\u003e, :password \"SecretABC\"}\n```\n\nThe `#unmask` tag does the opposite: unwraps a masked value:\n\n```clojure\n(def token (mask \"secret123\"))\n\n#unmask token\n;; \"secret123\"\n```\n\n### EDN tag\n\nThere is a `reader-edn` function that acts like an EDN reader for the same tag:\n\n```clojure\n(let [source (-\u003e \"{:foo #mask 42}\")]\n  (edn/read-string {:readers {'mask reader-edn}}\n                   source))\n\n;; {:foo \u003c\u003c masked \u003e\u003e}\n```\n\n### Aero tag\n\nTo extend Aero with the `#mask` tag, import the `mask.aero` namespace:\n\n```clojure\n(require 'mask.aero)\n```\n\nThen read a config with the tag:\n\n```clojure\n;; config.edn\n{:foo #mask #env \"SOME_PASSWORD\"}\n\n;; code\n(aero/read-config (io/resource \"config.edn\"))\n\n;; {:foo \u003c\u003c masked \u003e\u003e}\n```\n\nThe Aero dependency is not included. You've got to provide it by your own.\n\n*Ivan Grishaev, 2023*\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Figrishaev%2Fmask","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Figrishaev%2Fmask","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Figrishaev%2Fmask/lists"}