{"id":17120179,"url":"https://github.com/milouse/edgar","last_synced_at":"2025-10-13T00:17:33.021Z","repository":{"id":77463467,"uuid":"246037537","full_name":"milouse/edgar","owner":"milouse","description":"A small utility to maintain SSH config files (Mirror)","archived":false,"fork":false,"pushed_at":"2023-12-07T21:27:42.000Z","size":50,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-13T00:17:32.634Z","etag":null,"topics":["configuration-management","ssh","sshconfig"],"latest_commit_sha":null,"homepage":"https://git.umaneti.net/edgar/about/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"wtfpl","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/milouse.png","metadata":{"files":{"readme":"README.org","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"liberapay":"milouse","custom":["https://paypal.me/milouse"]}},"created_at":"2020-03-09T13:05:15.000Z","updated_at":"2022-12-14T23:13:26.000Z","dependencies_parsed_at":null,"dependency_job_id":"95a6ad5e-a31e-4cf6-8393-97bbfe9ac643","html_url":"https://github.com/milouse/edgar","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/milouse/edgar","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/milouse%2Fedgar","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/milouse%2Fedgar/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/milouse%2Fedgar/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/milouse%2Fedgar/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/milouse","download_url":"https://codeload.github.com/milouse/edgar/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/milouse%2Fedgar/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279013621,"owners_count":26085298,"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","status":"online","status_checked_at":"2025-10-12T02:00:06.719Z","response_time":53,"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":["configuration-management","ssh","sshconfig"],"created_at":"2024-10-14T17:59:15.010Z","updated_at":"2025-10-13T00:17:32.988Z","avatar_url":"https://github.com/milouse.png","language":"Python","funding_links":["https://liberapay.com/milouse","https://paypal.me/milouse"],"categories":[],"sub_categories":[],"readme":"#+title: Edgar\n\n~edgar~ is a small utility to help one maintain their huge SSH config\nfile. It's heavilly inspired by [[https://github.com/9seconds/concierge][concierge]] (even the tests are directly\ntaken from the ~concierge~ examples!).\n\n* Installation\n\n~edgar~ only support python3. We are now in 2019!\n\n#+begin_src sh\npython -m venv edgar-venv\nsource edgar-venv/bin/activate\npython setup.py install\n#+end_src\n\nUnit tests can be run with ~python -m unittest~.\n\n* Usage\n\nContrary to ~concierge~, there is no inotify support. The main idea is\nthat you are not always modifying your SSH config file and it's not that\nhard to just call manually ~edgar~ when your config template is ready.\n\n~edgar~ rely on a config file stored in your =~/.config= folder:\n=~/.config/edgar.yml=. As its name show it, this is a YAML file.\n\nThis file should contain a list of host configurations. Thus the most\nsimple config file may be:\n\n#+begin_src conf\n---\n- Host: m1\n  Hostname: 192.168.1.42\n  User: edgar\n- Host: m2\n  Hostname: 192.168.1.43\n  User: edgar\n#+end_src\n\nWhich will output the following:\n\n#+begin_src conf\nHost m1\n  Hostname 192.168.1.42\n  User edgar\n\nHost m2\n  Hostname 192.168.1.43\n  User edgar\n#+end_src\n\nIf the main object is not a list, it is taken as a primary host\nconfiguration named ~*~:\n\n#+begin_src conf\n---\nCheckHostIP: yes\nCompression: yes\nStrictHostKeyChecking: accept-new\nServerAliveInterval: 120\nServerAliveCountMax: 2\nHashKnownHosts: yes\nIdentitiesOnly: yes\nAddKeysToAgent: yes\n\nhosts:\n  - Host: m1\n    Hostname: 192.168.1.42\n    User: edgar\n  - Host: m2\n    Hostname: 192.168.1.43\n    User: edgar\n#+end_src\n\nWhich will output the following:\n\n#+begin_src conf\nHost m1\n  Hostname 192.168.1.42\n  User edgar\n\nHost m2\n  Hostname 192.168.1.43\n  User edgar\n\nHost *\n  AddKeysToAgent yes\n  CheckHostIP yes\n  Compression yes\n  HashKnownHosts yes\n  IdentitiesOnly yes\n  ServerAliveCountMax 2\n  ServerAliveInterval 120\n  StrictHostKeyChecking accept-new\n#+end_src\n\nFinally, ~edgar~ understands sub-hosts and ansible-like ~with_items~\nprocessing:\n\n#+begin_src conf\n---\nCheckHostIP: yes\nCompression: yes\nStrictHostKeyChecking: accept-new\nServerAliveInterval: 120\nServerAliveCountMax: 2\nHashKnownHosts: yes\nIdentitiesOnly: yes\nAddKeysToAgent: yes\n\nhosts:\n  - Host: m\n    User: edgar\n    hide: yes\n    hosts:\n      - Host: e{item}\n        Hostname: 10.10.0.{item}\n        ViaProxy: gw2\n        with_items: range(2)\n  - Host: blog\n    User: sa\n#+end_src\n\nWhich will output the following:\n\n#+begin_src conf\nHost me0\n  Hostname 10.10.0.0\n  ProxyCommand ssh -W %h:%p gw2\n  User edgar\n\nHost me1\n  Hostname 10.10.0.1\n  ProxyCommand ssh -W %h:%p gw2\n  User edgar\n\nHost blog\n  User sa\n\nHost *\n  AddKeysToAgent yes\n  CheckHostIP yes\n  Compression yes\n  HashKnownHosts yes\n  IdentitiesOnly yes\n  ServerAliveCountMax 2\n  ServerAliveInterval 120\n  StrictHostKeyChecking accept-new\n#+end_src\n\n* Reference\n\n~edgar~ understands all config options from an up-to-date OpenSSH config\noptions list. As for OpenSSH itself, option names are case\ninsensitive. However, during config generation process, option names will be\nwritten following the OpenSSH naming convention and alphabetically sorted\nunder ~Host~ or ~Match~ blocks. The ~Host~ and ~Match~ blocks order is kept as\nprovided, but all \"orphaned\" options are gathered inside a single ~Host *~\nblock, which is always output last.\n\nIt also understands the following supplementary options:\n\n- ~blocks~ :: define a listing of ~Host~ or ~Match~ block, each of them will\n  inherit from the current block parameters. For historical reason, this\n  option can be named ~hosts~, but this is deprecated.\n- ~hide~ :: Whether a specific configuration for the current block should be\n  output or if it should be only used for factorization purpose of its\n  sub-block. Value must be a boolean. Default is ~no~ (false).\n- ~prefix~ :: Whether the current block name should be concatenated with it's\n  sub-blocks name. Value must be a boolean. Default is ~yes~ (true).\n- ~with_items~ :: define that the current block configuration must be\n  duplicated for each item of this list. Value must be something python is\n  able to iterate over (a list, a range expression…). You can use the ~{item}~\n  tag in any option value of the same block.\n- ~ViaProxy \u003chost\u003e~ :: shortcut helper, which expands to\n  ~ProxyCommand ssh -W %h:%p \u003chost\u003e~.\n\n* FAQ\n\n- *Edgar crash with a weird error message about YAML parser*\n  1. Don't forget to add the colon between the SSH parameter and its\n     value.\n  2. Some values must be protected, like the one with ~*~. For exemple:\n     ~Host: \"*.toto.com\"~.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmilouse%2Fedgar","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmilouse%2Fedgar","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmilouse%2Fedgar/lists"}