{"id":13821184,"url":"https://github.com/scopely-devops/skew","last_synced_at":"2025-12-14T17:37:25.445Z","repository":{"id":43183543,"uuid":"20736773","full_name":"scopely-devops/skew","owner":"scopely-devops","description":null,"archived":false,"fork":false,"pushed_at":"2022-03-14T18:59:10.000Z","size":369,"stargazers_count":240,"open_issues_count":25,"forks_count":70,"subscribers_count":25,"default_branch":"develop","last_synced_at":"2025-09-29T15:09:30.547Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/scopely-devops.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}},"created_at":"2014-06-11T18:47:53.000Z","updated_at":"2025-09-05T23:50:23.000Z","dependencies_parsed_at":"2022-08-31T15:02:27.664Z","dependency_job_id":null,"html_url":"https://github.com/scopely-devops/skew","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/scopely-devops/skew","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scopely-devops%2Fskew","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scopely-devops%2Fskew/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scopely-devops%2Fskew/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scopely-devops%2Fskew/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/scopely-devops","download_url":"https://codeload.github.com/scopely-devops/skew/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scopely-devops%2Fskew/sbom","scorecard":{"id":805278,"data":{"date":"2025-08-11","repo":{"name":"github.com/scopely-devops/skew","commit":"dd6b6621d5737633d64631687418b3f29a1f6063"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.5,"checks":[{"name":"Code-Review","score":3,"reason":"Found 5/16 approved changesets -- score normalized to 3","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/python-package.yml:1","Warn: no topLevel permission defined: .github/workflows/python-publish.yml:1","Warn: no topLevel permission defined: .github/workflows/python-validate.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/python-package.yml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/scopely-devops/skew/python-package.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/python-package.yml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/scopely-devops/skew/python-package.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/python-publish.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/scopely-devops/skew/python-publish.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/python-publish.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/scopely-devops/skew/python-publish.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/python-validate.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/scopely-devops/skew/python-validate.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/python-validate.yml:20: update your workflow using https://app.stepsecurity.io/secureworkflow/scopely-devops/skew/python-validate.yml/develop?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/python-package.yml:28","Warn: pipCommand not pinned by hash: .github/workflows/python-package.yml:29","Warn: pipCommand not pinned by hash: .github/workflows/python-package.yml:30","Warn: pipCommand not pinned by hash: .github/workflows/python-publish.yml:23","Warn: pipCommand not pinned by hash: .github/workflows/python-publish.yml:24","Warn: pipCommand not pinned by hash: .github/workflows/python-validate.yml:25","Warn: pipCommand not pinned by hash: .github/workflows/python-validate.yml:26","Warn: pipCommand not pinned by hash: .github/workflows/python-validate.yml:27","Warn: pipCommand not pinned by hash: .github/workflows/python-validate.yml:30","Info:   0 out of   6 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   9 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Vulnerabilities","score":8,"reason":"2 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2021-142 / GHSA-8q59-q68h-6hv4","Warn: Project is vulnerable to: PYSEC-2018-49 / GHSA-rprw-h62v-c2w7"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 21 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'develop'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-23T11:36:29.525Z","repository_id":43183543,"created_at":"2025-08-23T11:36:29.526Z","updated_at":"2025-08-23T11:36:29.526Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27732502,"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-12-14T02:00:11.348Z","response_time":56,"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":"2024-08-04T08:01:17.012Z","updated_at":"2025-12-14T17:37:25.399Z","avatar_url":"https://github.com/scopely-devops.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"# skew\n\n![PyPI](https://img.shields.io/pypi/v/skew) https://pypi.org/project/skew/\n\n`Skew` is a package for identifying and enumerating cloud resources.\nThe name is a homonym for SKU (Stock Keeping Unit).  Skew allows you to\ndefine different SKU `schemes` which are a particular encoding of a\nSKU.  Skew then allows you to use this scheme pattern and regular expressions\nbased on the scheme pattern to identify and enumerate a resource or set\nof resources.\n\nAt the moment, the the only available `scheme` is the `ARN` scheme.\nThe `ARN` scheme uses the basic structure of\n[Amazon Resource Names](http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) (ARNs) to assign a unique identifier to every AWS\nresource.\n\nAn example ARN pattern would be:\n\n```\narn:aws:ec2:us-west-2:123456789012:instance/i-12345678\n```\n\nThis pattern identifies a specific EC2 instance running in the `us-west-2`\nregion under the account ID `123456789012`.  The account ID is the 12-digit\nunique identifier for a specific AWS account as described\n[here](http://docs.aws.amazon.com/general/latest/gr/acct-identifiers.html).\nTo allow `skew` to find your account number, you need to create a `skew`\nYAML config file.  By default, `skew` will look for your config file in\n`~/.skew` but you can use the `SKEW_CONFIG` environment variable to tell `skew`\nwhere to find your config file if you choose to put it somewhere else.  The\nbasic format of the `skew` config file is:\n\n```yaml\n---\n  accounts:\n    \"123456789012\":\n      profile: dev\n    \"234567890123\":\n      profile: prod\n```\n\nWithin the `accounts` section, you create keys named after your 12-digit\naccount ID (as a string).  Within that, you must have an entry called *profile*\nthat lists the profile name this account maps to within your AWS credential\nfile.\n\nThe main purpose of skew is to identify resources or sets of resources\nacross services, regions, and accounts and to quickly and easily return the\ndata associated with those resources. For example, if you wanted to return\nthe data associated with the example ARN above:\n\n```python\nfrom skew import scan\n\narn = scan('arn:aws:ec2:us-west-2:123456789012:instance/i-12345678')\nfor resource in arn:\n    print(resource.data)\n```\n\nThe call to `scan` returns an ARN object which implements the\n[iterator pattern](https://docs.python.org/2/library/stdtypes.html#iterator-types)\nand returns a `Resource` object for each AWS resource that matches the\nARN pattern provided.  The `Resource` object contains all of the data\nassociated with the AWS resource in dictionary under the `data` attribute.\n\nAny of the elements of the ARN can be replaced with a regular expression.\nThe simplest regular expression is `*` which means all available choices.\nSo, for example:\n\n```python\narn = scan('arn:aws:ec2:us-east-1:*:instance/*')\n```\n\nwould return an iterator for all EC2 instances in the `us-east-1` region\nfound in all accounts defined in the config file.\n\nTo find all DynamoDB tables in all US regions for the account ID 234567890123\nyou would use:\n\n```python\narn = scan('arn:aws:dynamodb:us-.*:234567890123:table/*')\n```\n\nCloudWatch Metrics\n------------------\n\nIn addition to making the metadata about a particular AWS resource available\nto you, `skew` also tries to make it easy to access the available CloudWatch\nmetrics for a given resource.\n\nFor example, assume that you had did a `scan` on the original ARN above\nand had the resource associated with that instance available as the variable\n`instance`.  You could do the following:\n\n```python\n\u003e\u003e\u003e instance.metric_names\n['CPUUtilization',\n 'NetworkOut',\n 'StatusCheckFailed',\n 'StatusCheckFailed_System',\n 'NetworkIn',\n 'DiskWriteOps',\n 'DiskReadBytes',\n 'DiskReadOps',\n 'StatusCheckFailed_Instance',\n 'DiskWriteBytes']\n\u003e\u003e\u003e\n```\n\nThe `metric_names` attribute returns the list of available CloudWatch metrics\nfor this resource.  The retrieve the metric data for one of these:\n\n```python\n\u003e\u003e\u003e instance.get_metric_data('CPUUtilization')\n[{'Average': 0.134, 'Timestamp': '2014-09-29T14:04:00Z', 'Unit': 'Percent'},\n {'Average': 0.066, 'Timestamp': '2014-09-29T13:54:00Z', 'Unit': 'Percent'},\n {'Average': 0.066, 'Timestamp': '2014-09-29T14:09:00Z', 'Unit': 'Percent'},\n {'Average': 0.134, 'Timestamp': '2014-09-29T13:34:00Z', 'Unit': 'Percent'},\n {'Average': 0.066, 'Timestamp': '2014-09-29T14:19:00Z', 'Unit': 'Percent'},\n {'Average': 0.068, 'Timestamp': '2014-09-29T13:44:00Z', 'Unit': 'Percent'},\n {'Average': 0.134, 'Timestamp': '2014-09-29T14:14:00Z', 'Unit': 'Percent'},\n {'Average': 0.066, 'Timestamp': '2014-09-29T13:29:00Z', 'Unit': 'Percent'},\n {'Average': 0.132, 'Timestamp': '2014-09-29T13:59:00Z', 'Unit': 'Percent'},\n {'Average': 0.134, 'Timestamp': '2014-09-29T13:49:00Z', 'Unit': 'Percent'},\n {'Average': 0.134, 'Timestamp': '2014-09-29T13:39:00Z', 'Unit': 'Percent'}]\n\u003e\u003e\u003e\n```\n\nYou can also customize the data returned rather than using the default settings:\n\n```python\n\u003e\u003e\u003e instance.get_metric_data('CPUUtilization', hours=8, statistics=['Average', 'Minimum', 'Maximum'])\n[{'Average': 0.132,\n  'Maximum': 0.33,\n  'Minimum': 0.0,\n  'Timestamp': '2014-09-29T10:54:00Z',\n  'Unit': 'Percent'},\n {'Average': 0.134,\n  'Maximum': 0.34,\n  'Minimum': 0.0,\n  'Timestamp': '2014-09-29T14:04:00Z',\n  'Unit': 'Percent'},\n  ...,\n {'Average': 0.066,\n  'Maximum': 0.33,\n  'Minimum': 0.0,\n  'Timestamp': '2014-09-29T08:34:00Z',\n  'Unit': 'Percent'},\n {'Average': 0.134,\n  'Maximum': 0.34,\n  'Minimum': 0.0,\n  'Timestamp': '2014-09-29T08:04:00Z',\n  'Unit': 'Percent'}]\n\u003e\u003e\u003e\n```\n\nFiltering Data\n--------------\n\nEach resource that is retrieved is a Python dictionary.  Some of these (e.g.\nan EC2 Instance) can be quite large and complex.  Skew allows you to filter\nthe data returned by applying a [jmespath](http://jmespath.org) query to\nthe resulting data.  If you aren't familiar with jmespath, check it out.\nIts a very powerful query language for JSON data and has full support in\nPython as well as a number of other languages such as Ruby, PHP, and\nJavascript.  It is also the query language used in the\n[AWSCLI](https://aws.amazon.com/cli/) so if you are familiar with the\n`--query` option there, you can use the same thing with skew.\n\nTo specify a query to be applied to results of a scan, simply append\nthe query to the end of the ARN, separated by a `|` (pipe) character.\nFor example:\n\n```\narn:aws:ec2:us-west-2:123456789012:instance/i-12345678|InstanceType\n```\n\nWould retrieve the data for this particular EC2 instance and would then\nfilter the returned data through the (very) simple jmespath query to which\nretrieves the value of the attribute `InstanceType` within the data.  The\nfiltered data is available as the `filtered_data` attribute of the\nResource object.  The full, unfiltered data is still available as the\n`data` attribute.\n\nMultithreaded Usage\n-------------------\n\nSkew is single-threaded by default, like most Python libraries. In order to\nspeed up the enumeration of matching resources, you can use multiple threads:\n\n```python\nimport skew\n\nclass Worker(Thread):\n   def __init__(self, arn):\n       Thread.__init__(self)\n       self.arn = arn\n       self.name = arn\n\n   def run(self):\n       for i in skew.scan(self.arn):\n           # now do something with the stuff\n\narn = skew.ARN()\n\nfor service in arn.service.choices():\n    uri = 'arn:aws:' + service + ':*:*:*/*'\n    worker = Worker(uri);\n    worker.start()\n```\n\n(thanks to @alFReD-NSH for the snippet)\n\nMore Examples\n-------------\n\n[Find Unattached Volumes](https://gist.github.com/garnaat/73804a6b0bd506ee6075)\n\n[Audit Security Groups](https://gist.github.com/garnaat/4123f1aefe7d65df9b48)\n\n[Find Untagged Instances](https://gist.github.com/garnaat/11004f5661b4798d27c7)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fscopely-devops%2Fskew","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fscopely-devops%2Fskew","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fscopely-devops%2Fskew/lists"}