{"id":16300457,"url":"https://github.com/melezhik/bird","last_synced_at":"2025-03-20T05:31:07.882Z","repository":{"id":47422289,"uuid":"197694234","full_name":"melezhik/bird","owner":"melezhik","description":"Bird - Alternative to Chef Inspec and Goss, written in Raku.","archived":false,"fork":false,"pushed_at":"2024-07-17T08:23:26.000Z","size":230,"stargazers_count":6,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-17T15:07:58.680Z","etag":null,"topics":["goss","inspec","raku","sparrow6","testinfra"],"latest_commit_sha":null,"homepage":"","language":"Raku","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/melezhik.png","metadata":{"files":{"readme":"README.md","changelog":"Changes","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"Roadmap.md","authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-07-19T03:19:25.000Z","updated_at":"2024-07-17T08:23:29.000Z","dependencies_parsed_at":"2024-10-27T22:19:20.973Z","dependency_job_id":null,"html_url":"https://github.com/melezhik/bird","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/melezhik%2Fbird","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/melezhik%2Fbird/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/melezhik%2Fbird/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/melezhik%2Fbird/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/melezhik","download_url":"https://codeload.github.com/melezhik/bird/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244559852,"owners_count":20472211,"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":["goss","inspec","raku","sparrow6","testinfra"],"created_at":"2024-10-10T20:51:17.978Z","updated_at":"2025-03-20T05:31:07.509Z","avatar_url":"https://github.com/melezhik.png","language":"Raku","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Bird 🐦\n\nBird - Raku DSL for Linux Servers Verification.\n\nIt's written in Raku and exposes pure Raku API.\n\n# WARNING ⚠️\n\nBird is under active development now, things might change.\n\n# Build Status\n\n[![SparrowCI](https://ci.sparrowhub.io/project/gh-melezhik-bird/badge)](https://ci.sparrowhub.io)\n\n# INSTALL\n\n    zef install Bird\n\nBird uses Sparrow6 plugin `ssh-bulk-check` to do it's work, so one needs\nto setup Sparrow6 repository:\n\n    export SP6_REPO=http://sparrowhub.io/repo\n\nTo run check remotely install ssh-pass:\n\n    sudo yum install sshpass\n\n# USAGE\n\nCreate rules:\n\n`cat rules.raku`\n\n```raku\ndirectory-exists \"{%*ENV\u003cHOME\u003e}\";\n\nfile-exists \"{%*ENV\u003cHOME\u003e}/.bashrc\";\n\nbash \"echo hello \u003e /tmp/bird.tmp\";\n\nbash \"echo bird \u003e\u003e /tmp/bird.tmp\";\n\nfile-has-line \"/tmp/bird.tmp\", \"hello\", \"bird\";\n\nfile-has-permission \"documentation/dsl.md\", %( read-all =\u003e True );\nfile-has-permission \"bin/bird\", %( execute-all =\u003e True, read-all =\u003e True );\n\nbash \"chmod a+r /tmp/bird.tmp\";\n\nbash \"chmod a+w /tmp/bird.tmp\";\n\nfile-has-permission \"/tmp/bird.tmp\", %( write-all =\u003e True, read-all =\u003e True );\n\ncommand-has-stdout \"echo hello; echo bird\", \"hello\", \"bird\";\n\ncommand-exit-code \"raku --version\", 0;\n\npackage-installed \"nano\";\n\npip3-package-installed \"PyYAML\";\n\nfile-has-permission \"rules.raku\", %( read-all =\u003e True );\n\npackage-installed \"nano\";\n\nbash \"echo username=admin \u003e /tmp/creds.txt; echo password=123 \u003e\u003e /tmp/creds.txt;\";\n\nfile-data-not-empty \"/tmp/creds.txt\",\n  \"username=\", \"password=\";\n```\n\nRun checks against hosts:\n\n`bird`\n\n```\nbird:: [read hosts from file] [hosts.raku]\nbird:: [cmd file] [/root/.bird/274302/cmd.sh]\nbird:: [check file] [/root/.bird/274302/state.check]\nbird:: [init cmd file]\n[bash: echo hello \u003e /tmp/bird.tmp] :: \u003cempty stdout\u003e\n[bash: echo bird \u003e\u003e /tmp/bird.tmp] :: \u003cempty stdout\u003e\n[bash: chmod a+r /tmp/bird.tmp] :: \u003cempty stdout\u003e\n[bash: chmod a+w /tmp/bird.tmp] :: \u003cempty stdout\u003e\n[bash: echo username=admin \u003e /tmp/creds.txt; echo passwor ...] :: \u003cempty stdout\u003e\n[repository] :: index updated from file:///root/repo/api/v1/index\n[check my hosts] :: check host [localhost]\n[check my hosts] :: ==========================================================\n[check my hosts] :: \u003c\u003c\u003c test_01: directory /root exists\n[check my hosts] :: directory /root exists\n[check my hosts] :: \u003e\u003e\u003e\n[check my hosts] :: \u003c\u003c\u003c test_02: file /root/.bashrc exists\n[check my hosts] :: file /root/.bashrc exists\n[check my hosts] :: \u003e\u003e\u003e\n[check my hosts] :: \u003c\u003c\u003c test_03: file /tmp/bird.tmp has lines\n[check my hosts] :: hello\n[check my hosts] :: bird\n[check my hosts] :: \u003e\u003e\u003e\n[check my hosts] :: \u003c\u003c\u003c test_04: file documentation/dsl.md is readable by all\n[check my hosts] :: -rw-r--r--\n[check my hosts] :: \u003e\u003e\u003e\n[check my hosts] :: \u003c\u003c\u003c test_05: file bin/bird is readable by all\n[check my hosts] :: -rwxr-xr-x\n[check my hosts] :: \u003e\u003e\u003e\n[check my hosts] :: \u003c\u003c\u003c test_06: file bin/bird is executable by all\n[check my hosts] :: -rwxr-xr-x\n[check my hosts] :: \u003e\u003e\u003e\n[check my hosts] :: \u003c\u003c\u003c test_07: file /tmp/bird.tmp is readable by all\n[check my hosts] :: -rw-rw-rw-\n[check my hosts] :: \u003e\u003e\u003e\n[check my hosts] :: \u003c\u003c\u003c test_08: file /tmp/bird.tmp is writable by all\n[check my hosts] :: -rw-rw-rw-\n[check my hosts] :: \u003e\u003e\u003e\n[check my hosts] :: \u003c\u003c\u003c test_09: command [echo hello; echo bird] has stdout\n[check my hosts] :: hello\n[check my hosts] :: bird\n[check my hosts] :: \u003e\u003e\u003e\n[check my hosts] :: \u003c\u003c\u003c test_10: command [raku --version] has exit code\n[check my hosts] :: command [raku --version] exit code [0]\n[check my hosts] :: \u003e\u003e\u003e\n[check my hosts] :: \u003c\u003c\u003c test_11: package(s) installed\n[check my hosts] :: Installed Packages\n[check my hosts] :: nano.x86_64                         2.9.8-1.el8                          @baseos\n[check my hosts] :: package nano is installed\n[check my hosts] :: \u003e\u003e\u003e\n[check my hosts] :: \u003c\u003c\u003c test_12: pip3 package(s) installed\n[check my hosts] :: PyYAML              3.12\n[check my hosts] :: \u003e\u003e\u003e\n[check my hosts] :: \u003c\u003c\u003c test_13: file rules.raku is readable by all\n[check my hosts] :: -rw-r--r--\n[check my hosts] :: \u003e\u003e\u003e\n[check my hosts] :: \u003c\u003c\u003c test_14: package(s) installed\n[check my hosts] :: Installed Packages\n[check my hosts] :: nano.x86_64                         2.9.8-1.el8                          @baseos\n[check my hosts] :: package nano is installed\n[check my hosts] :: \u003e\u003e\u003e\n[check my hosts] :: \u003c\u003c\u003c test_15: file /tmp/creds.txt data not empty\n[check my hosts] :: \u003e\u003e\u003e username=[censored]\n[check my hosts] :: \u003e\u003e\u003e password=[censored]\n[check my hosts] :: \u003e\u003e\u003e\n[check my hosts] :: end check host [localhost]\n[check my hosts] :: ==========================================================\n[task check] verify host [localhost] start\n[task check] test_01: directory /root exists\n[task check] stdout match (r) \u003cdirectory /root exists\u003e True\n[task check] test_02: file /root/.bashrc exists\n[task check] stdout match (r) \u003cfile /root/.bashrc exists\u003e True\n[task check] test_03: file /tmp/bird.tmp has lines [\"hello\", \"bird\"]\n[task check] stdout match (r) \u003chello\u003e True\n[task check] stdout match (r) \u003cbird\u003e True\n[task check] test_04: file documentation/dsl.md is readable by all\n[task check] stdout match (r) \u003c^^^ \\S \"r\"\\S\\S \"r\"\\S\\S \"r\"\\S\\S $$\u003e True\n[task check] test_05: file bin/bird is readable by all\n[task check] stdout match (r) \u003c^^^ \\S \"r\"\\S\\S \"r\"\\S\\S \"r\"\\S\\S $$\u003e True\n[task check] test_06: file bin/bird is executable by all\n[task check] stdout match (r) \u003c^^^ \\S  \\S\\S\"x\"  \\S\\S\"x\" \\S\\S\"x\" $$\u003e True\n[task check] test_07: file /tmp/bird.tmp is readable by all\n[task check] stdout match (r) \u003c^^^ \\S \"r\"\\S\\S \"r\"\\S\\S \"r\"\\S\\S $$\u003e True\n[task check] test_08: file /tmp/bird.tmp is writable by all\n[task check] stdout match (r) \u003c^^^ \\S  \\S\"w\"\\S  \\S\"w\"\\S \\S\"w\"\\S $$\u003e True\n[task check] test_09: command [echo hello; echo bird] has stdout\n[task check] [\"hello\", \"bird\"]\n[task check] stdout match (r) \u003chello\u003e True\n[task check] stdout match (r) \u003cbird\u003e True\n[task check] test_10: command [raku --version] has exit code [0]\n[task check] stdout match (r) \u003ccommand [raku --version] exit code [0]\u003e True\n[task check] test_11: package(s) installed \"nano\"\n[task check] stdout match (r) \u003cpackage nano is installed\u003e True\n[task check] test_12: pip3 package(s) installed \"PyYAML\"\n[task check] stdout match (r) \u003c^^ 'PyYAML' \\s+\u003e True\n[task check] test_13: file rules.raku is readable by all\n[task check] stdout match (r) \u003c^^^ \\S \"r\"\\S\\S \"r\"\\S\\S \"r\"\\S\\S $$\u003e True\n[task check] test_14: package(s) installed \"nano\"\n[task check] stdout match (r) \u003cpackage nano is installed\u003e True\n[task check] test_15: file /tmp/creds.txt data not empty [\"username=\", \"password=\"]\n[task check] stdout match (r) \u003c^^ '\u003e\u003e\u003e'\u003e True\n[task check] \u003c\u003e\u003e\u003e username=[censored] is not empty\u003e True\n[task check] \u003c\u003e\u003e\u003e password=[censored] is not empty\u003e True\n[task check] verify host [localhost] end\n```\n\n# Rules DSL\n\nRules DSL is special language to validate states of Linux host.\n\nThis is just plain Raku functions:\n\n    file-exists \"{%*ENV\u003cHOME\u003e}/.bashrc\";\n\nThe full list of DSL functions available [here](https://github.com/melezhik/bird/blob/master/documentation/dsl.md).\n\n# Ssh hosts\n\nThere are two ways to set ssh hosts:\n\n## Command line\n\nBy using `--host`, `--user`, `--password` options:\n\n    bird --host=192.168.0.1 --user=alex --password=PasSword\n\n## Hosts.raku\n\nTo define dynamic hosts configuration, use `hosts.raku`, this should\nbe Raku script that returns `@Array` of hosts:\n\n    [\n      '192.168.0.1',\n      'foo.bar.baz',\n      # so on\n    ]\n\nFor example:\n\n    use Sparrow6::DSL;\n\n    my %state = task-run \"worker nodes\", \"ambari-hosts\", %(\n      ambari_host  =\u003e 'cluster.fqdn.host',\n      admin =\u003e 'super-jack',\n      password =\u003e 'PaSsWord123',\n      cluster =\u003e \"cluster01\",\n      node_type =\u003e \"worker\",\n    );\n\n    %state\u003chosts\u003e\u003c\u003e.map: { %i\u003cip\u003e }\n\n# cli options\n\n* `--rules`\n\nPath to rules file. If not set `rules.pl` in cwd is taken\n\n\n* `--password`\n\nSsh password. Optional\n\n* `--user`\n\nSsh user. Optional\n\n* `--host`\n\nSsh host. Optional, see also `hosts.raku`\n\n* `--nocolor`\n\nDisable color output. Optional\n\n* `--debug`\n\nDebug mode (produce a lot of useful, but low level info). Optional\n\n# Examples\n\nSee:\n\n* `rules.raku` file\n\n* `rules/` folder\n\n# Author\n\nAlexey Melezhik\n\n# See Also\n\n* [Chef Inspec](https://www.inspec.io/)\n* [Goss](https://github.com/aelsabbahy/goss)\n\n# Thanks to\n\nGod Who inspires me in my life!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmelezhik%2Fbird","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmelezhik%2Fbird","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmelezhik%2Fbird/lists"}