diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 0000000000..9c970828cf --- /dev/null +++ b/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 20c30e1e72d3581b39cb4679c80b9b22 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.doctrees/contact.doctree b/.doctrees/contact.doctree new file mode 100644 index 0000000000..d01254a478 Binary files /dev/null and b/.doctrees/contact.doctree differ diff --git a/.doctrees/dev/developer-guide.doctree b/.doctrees/dev/developer-guide.doctree new file mode 100644 index 0000000000..9f3365107b Binary files /dev/null and b/.doctrees/dev/developer-guide.doctree differ diff --git a/.doctrees/dev/index.doctree b/.doctrees/dev/index.doctree new file mode 100644 index 0000000000..8964fe9ac0 Binary files /dev/null and b/.doctrees/dev/index.doctree differ diff --git a/.doctrees/dev/testing-with-docker.doctree b/.doctrees/dev/testing-with-docker.doctree new file mode 100644 index 0000000000..fa3a23888c Binary files /dev/null and b/.doctrees/dev/testing-with-docker.doctree differ diff --git a/.doctrees/dev/writing-analysis-jobs.doctree b/.doctrees/dev/writing-analysis-jobs.doctree new file mode 100644 index 0000000000..b60c7d06de Binary files /dev/null and b/.doctrees/dev/writing-analysis-jobs.doctree differ diff --git a/.doctrees/dev/writing-intel-modules.doctree b/.doctrees/dev/writing-intel-modules.doctree new file mode 100644 index 0000000000..6aa5de8b68 Binary files /dev/null and b/.doctrees/dev/writing-intel-modules.doctree differ diff --git a/.doctrees/environment.pickle b/.doctrees/environment.pickle new file mode 100644 index 0000000000..f6fe15edd4 Binary files /dev/null and b/.doctrees/environment.pickle differ diff --git a/.doctrees/index.doctree b/.doctrees/index.doctree new file mode 100644 index 0000000000..c64c21ba9a Binary files /dev/null and b/.doctrees/index.doctree differ diff --git a/.doctrees/info.doctree b/.doctrees/info.doctree new file mode 100644 index 0000000000..4023c8c574 Binary files /dev/null and b/.doctrees/info.doctree differ diff --git a/.doctrees/install.doctree b/.doctrees/install.doctree new file mode 100644 index 0000000000..19ea3ca37a Binary files /dev/null and b/.doctrees/install.doctree differ diff --git a/.doctrees/modules/_cartography-metadata/schema.doctree b/.doctrees/modules/_cartography-metadata/schema.doctree new file mode 100644 index 0000000000..55c02be6d9 Binary files /dev/null and b/.doctrees/modules/_cartography-metadata/schema.doctree differ diff --git a/.doctrees/modules/aws/config.doctree b/.doctrees/modules/aws/config.doctree new file mode 100644 index 0000000000..38145e4b28 Binary files /dev/null and b/.doctrees/modules/aws/config.doctree differ diff --git a/.doctrees/modules/aws/index.doctree b/.doctrees/modules/aws/index.doctree new file mode 100644 index 0000000000..501394eadc Binary files /dev/null and b/.doctrees/modules/aws/index.doctree differ diff --git a/.doctrees/modules/aws/permissions-mapping.doctree b/.doctrees/modules/aws/permissions-mapping.doctree new file mode 100644 index 0000000000..83c41ccade Binary files /dev/null and b/.doctrees/modules/aws/permissions-mapping.doctree differ diff --git a/.doctrees/modules/aws/schema.doctree b/.doctrees/modules/aws/schema.doctree new file mode 100644 index 0000000000..c3a6801ee9 Binary files /dev/null and b/.doctrees/modules/aws/schema.doctree differ diff --git a/.doctrees/modules/azure/config.doctree b/.doctrees/modules/azure/config.doctree new file mode 100644 index 0000000000..972c45b6bb Binary files /dev/null and b/.doctrees/modules/azure/config.doctree differ diff --git a/.doctrees/modules/azure/index.doctree b/.doctrees/modules/azure/index.doctree new file mode 100644 index 0000000000..577c5cc39d Binary files /dev/null and b/.doctrees/modules/azure/index.doctree differ diff --git a/.doctrees/modules/azure/schema.doctree b/.doctrees/modules/azure/schema.doctree new file mode 100644 index 0000000000..51e64008de Binary files /dev/null and b/.doctrees/modules/azure/schema.doctree differ diff --git a/.doctrees/modules/bigfix/config.doctree b/.doctrees/modules/bigfix/config.doctree new file mode 100644 index 0000000000..acf11c2a9a Binary files /dev/null and b/.doctrees/modules/bigfix/config.doctree differ diff --git a/.doctrees/modules/bigfix/index.doctree b/.doctrees/modules/bigfix/index.doctree new file mode 100644 index 0000000000..fa8dc5121c Binary files /dev/null and b/.doctrees/modules/bigfix/index.doctree differ diff --git a/.doctrees/modules/bigfix/schema.doctree b/.doctrees/modules/bigfix/schema.doctree new file mode 100644 index 0000000000..20241e0d3c Binary files /dev/null and b/.doctrees/modules/bigfix/schema.doctree differ diff --git a/.doctrees/modules/crowdstrike/config.doctree b/.doctrees/modules/crowdstrike/config.doctree new file mode 100644 index 0000000000..84b5ff56d2 Binary files /dev/null and b/.doctrees/modules/crowdstrike/config.doctree differ diff --git a/.doctrees/modules/crowdstrike/index.doctree b/.doctrees/modules/crowdstrike/index.doctree new file mode 100644 index 0000000000..2f69d93f72 Binary files /dev/null and b/.doctrees/modules/crowdstrike/index.doctree differ diff --git a/.doctrees/modules/crowdstrike/schema.doctree b/.doctrees/modules/crowdstrike/schema.doctree new file mode 100644 index 0000000000..7435ff1feb Binary files /dev/null and b/.doctrees/modules/crowdstrike/schema.doctree differ diff --git a/.doctrees/modules/crxcavator/config.doctree b/.doctrees/modules/crxcavator/config.doctree new file mode 100644 index 0000000000..afdec13462 Binary files /dev/null and b/.doctrees/modules/crxcavator/config.doctree differ diff --git a/.doctrees/modules/crxcavator/index.doctree b/.doctrees/modules/crxcavator/index.doctree new file mode 100644 index 0000000000..5dc59aedd7 Binary files /dev/null and b/.doctrees/modules/crxcavator/index.doctree differ diff --git a/.doctrees/modules/crxcavator/schema.doctree b/.doctrees/modules/crxcavator/schema.doctree new file mode 100644 index 0000000000..8029a840bd Binary files /dev/null and b/.doctrees/modules/crxcavator/schema.doctree differ diff --git a/.doctrees/modules/cve/config.doctree b/.doctrees/modules/cve/config.doctree new file mode 100644 index 0000000000..f49426eac8 Binary files /dev/null and b/.doctrees/modules/cve/config.doctree differ diff --git a/.doctrees/modules/cve/index.doctree b/.doctrees/modules/cve/index.doctree new file mode 100644 index 0000000000..0af1b7881c Binary files /dev/null and b/.doctrees/modules/cve/index.doctree differ diff --git a/.doctrees/modules/cve/schema.doctree b/.doctrees/modules/cve/schema.doctree new file mode 100644 index 0000000000..2024c24afb Binary files /dev/null and b/.doctrees/modules/cve/schema.doctree differ diff --git a/.doctrees/modules/digitalocean/config.doctree b/.doctrees/modules/digitalocean/config.doctree new file mode 100644 index 0000000000..ff7a3a4bd1 Binary files /dev/null and b/.doctrees/modules/digitalocean/config.doctree differ diff --git a/.doctrees/modules/digitalocean/index.doctree b/.doctrees/modules/digitalocean/index.doctree new file mode 100644 index 0000000000..8f032980cb Binary files /dev/null and b/.doctrees/modules/digitalocean/index.doctree differ diff --git a/.doctrees/modules/digitalocean/schema.doctree b/.doctrees/modules/digitalocean/schema.doctree new file mode 100644 index 0000000000..e2b9721fc1 Binary files /dev/null and b/.doctrees/modules/digitalocean/schema.doctree differ diff --git a/.doctrees/modules/duo/config.doctree b/.doctrees/modules/duo/config.doctree new file mode 100644 index 0000000000..efc52f3d95 Binary files /dev/null and b/.doctrees/modules/duo/config.doctree differ diff --git a/.doctrees/modules/duo/index.doctree b/.doctrees/modules/duo/index.doctree new file mode 100644 index 0000000000..9c53601998 Binary files /dev/null and b/.doctrees/modules/duo/index.doctree differ diff --git a/.doctrees/modules/duo/schema.doctree b/.doctrees/modules/duo/schema.doctree new file mode 100644 index 0000000000..97674f2218 Binary files /dev/null and b/.doctrees/modules/duo/schema.doctree differ diff --git a/.doctrees/modules/gcp/config.doctree b/.doctrees/modules/gcp/config.doctree new file mode 100644 index 0000000000..b4e94b92b8 Binary files /dev/null and b/.doctrees/modules/gcp/config.doctree differ diff --git a/.doctrees/modules/gcp/index.doctree b/.doctrees/modules/gcp/index.doctree new file mode 100644 index 0000000000..152ff2dabd Binary files /dev/null and b/.doctrees/modules/gcp/index.doctree differ diff --git a/.doctrees/modules/gcp/schema.doctree b/.doctrees/modules/gcp/schema.doctree new file mode 100644 index 0000000000..d9fdd461c8 Binary files /dev/null and b/.doctrees/modules/gcp/schema.doctree differ diff --git a/.doctrees/modules/github/config.doctree b/.doctrees/modules/github/config.doctree new file mode 100644 index 0000000000..25551c7891 Binary files /dev/null and b/.doctrees/modules/github/config.doctree differ diff --git a/.doctrees/modules/github/index.doctree b/.doctrees/modules/github/index.doctree new file mode 100644 index 0000000000..77026bf23c Binary files /dev/null and b/.doctrees/modules/github/index.doctree differ diff --git a/.doctrees/modules/github/schema.doctree b/.doctrees/modules/github/schema.doctree new file mode 100644 index 0000000000..c86bdb7a27 Binary files /dev/null and b/.doctrees/modules/github/schema.doctree differ diff --git a/.doctrees/modules/gsuite/config.doctree b/.doctrees/modules/gsuite/config.doctree new file mode 100644 index 0000000000..446efa5ba6 Binary files /dev/null and b/.doctrees/modules/gsuite/config.doctree differ diff --git a/.doctrees/modules/gsuite/index.doctree b/.doctrees/modules/gsuite/index.doctree new file mode 100644 index 0000000000..af14bb3849 Binary files /dev/null and b/.doctrees/modules/gsuite/index.doctree differ diff --git a/.doctrees/modules/gsuite/schema.doctree b/.doctrees/modules/gsuite/schema.doctree new file mode 100644 index 0000000000..748a711504 Binary files /dev/null and b/.doctrees/modules/gsuite/schema.doctree differ diff --git a/.doctrees/modules/index.doctree b/.doctrees/modules/index.doctree new file mode 100644 index 0000000000..e2fca1159f Binary files /dev/null and b/.doctrees/modules/index.doctree differ diff --git a/.doctrees/modules/jamf/index.doctree b/.doctrees/modules/jamf/index.doctree new file mode 100644 index 0000000000..69a005f511 Binary files /dev/null and b/.doctrees/modules/jamf/index.doctree differ diff --git a/.doctrees/modules/jamf/schema.doctree b/.doctrees/modules/jamf/schema.doctree new file mode 100644 index 0000000000..68d58313e3 Binary files /dev/null and b/.doctrees/modules/jamf/schema.doctree differ diff --git a/.doctrees/modules/kubernetes/config.doctree b/.doctrees/modules/kubernetes/config.doctree new file mode 100644 index 0000000000..d4b4872f24 Binary files /dev/null and b/.doctrees/modules/kubernetes/config.doctree differ diff --git a/.doctrees/modules/kubernetes/index.doctree b/.doctrees/modules/kubernetes/index.doctree new file mode 100644 index 0000000000..f3f0b084fd Binary files /dev/null and b/.doctrees/modules/kubernetes/index.doctree differ diff --git a/.doctrees/modules/kubernetes/schema.doctree b/.doctrees/modules/kubernetes/schema.doctree new file mode 100644 index 0000000000..dda386f6cc Binary files /dev/null and b/.doctrees/modules/kubernetes/schema.doctree differ diff --git a/.doctrees/modules/lastpass/config.doctree b/.doctrees/modules/lastpass/config.doctree new file mode 100644 index 0000000000..08844b1a93 Binary files /dev/null and b/.doctrees/modules/lastpass/config.doctree differ diff --git a/.doctrees/modules/lastpass/index.doctree b/.doctrees/modules/lastpass/index.doctree new file mode 100644 index 0000000000..7ebfd618d0 Binary files /dev/null and b/.doctrees/modules/lastpass/index.doctree differ diff --git a/.doctrees/modules/lastpass/schema.doctree b/.doctrees/modules/lastpass/schema.doctree new file mode 100644 index 0000000000..198844d22a Binary files /dev/null and b/.doctrees/modules/lastpass/schema.doctree differ diff --git a/.doctrees/modules/okta/config.doctree b/.doctrees/modules/okta/config.doctree new file mode 100644 index 0000000000..29acf0cb68 Binary files /dev/null and b/.doctrees/modules/okta/config.doctree differ diff --git a/.doctrees/modules/okta/index.doctree b/.doctrees/modules/okta/index.doctree new file mode 100644 index 0000000000..9ab4349e8c Binary files /dev/null and b/.doctrees/modules/okta/index.doctree differ diff --git a/.doctrees/modules/okta/schema.doctree b/.doctrees/modules/okta/schema.doctree new file mode 100644 index 0000000000..525a83b461 Binary files /dev/null and b/.doctrees/modules/okta/schema.doctree differ diff --git a/.doctrees/modules/pagerduty/config.doctree b/.doctrees/modules/pagerduty/config.doctree new file mode 100644 index 0000000000..6308222e65 Binary files /dev/null and b/.doctrees/modules/pagerduty/config.doctree differ diff --git a/.doctrees/modules/pagerduty/index.doctree b/.doctrees/modules/pagerduty/index.doctree new file mode 100644 index 0000000000..3270fc4823 Binary files /dev/null and b/.doctrees/modules/pagerduty/index.doctree differ diff --git a/.doctrees/modules/pagerduty/schema.doctree b/.doctrees/modules/pagerduty/schema.doctree new file mode 100644 index 0000000000..1b03c06fa3 Binary files /dev/null and b/.doctrees/modules/pagerduty/schema.doctree differ diff --git a/.doctrees/modules/semgrep/config.doctree b/.doctrees/modules/semgrep/config.doctree new file mode 100644 index 0000000000..906838d3ea Binary files /dev/null and b/.doctrees/modules/semgrep/config.doctree differ diff --git a/.doctrees/modules/semgrep/index.doctree b/.doctrees/modules/semgrep/index.doctree new file mode 100644 index 0000000000..bb1bb77db0 Binary files /dev/null and b/.doctrees/modules/semgrep/index.doctree differ diff --git a/.doctrees/modules/semgrep/schema.doctree b/.doctrees/modules/semgrep/schema.doctree new file mode 100644 index 0000000000..ab21c94d0a Binary files /dev/null and b/.doctrees/modules/semgrep/schema.doctree differ diff --git a/.doctrees/ops.doctree b/.doctrees/ops.doctree new file mode 100644 index 0000000000..9f3bffc06d Binary files /dev/null and b/.doctrees/ops.doctree differ diff --git a/.doctrees/usage/drift-detect.doctree b/.doctrees/usage/drift-detect.doctree new file mode 100644 index 0000000000..8630db54fa Binary files /dev/null and b/.doctrees/usage/drift-detect.doctree differ diff --git a/.doctrees/usage/index.doctree b/.doctrees/usage/index.doctree new file mode 100644 index 0000000000..473f2216b3 Binary files /dev/null and b/.doctrees/usage/index.doctree differ diff --git a/.doctrees/usage/samplequeries.doctree b/.doctrees/usage/samplequeries.doctree new file mode 100644 index 0000000000..b3dd174508 Binary files /dev/null and b/.doctrees/usage/samplequeries.doctree differ diff --git a/.doctrees/usage/schema.doctree b/.doctrees/usage/schema.doctree new file mode 100644 index 0000000000..b16fd69645 Binary files /dev/null and b/.doctrees/usage/schema.doctree differ diff --git a/.doctrees/usage/tutorial.doctree b/.doctrees/usage/tutorial.doctree new file mode 100644 index 0000000000..7d88d344d1 Binary files /dev/null and b/.doctrees/usage/tutorial.doctree differ diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000000..e69de29bb2 diff --git a/_images/accountsandrds.png b/_images/accountsandrds.png new file mode 100644 index 0000000000..a631b9749e Binary files /dev/null and b/_images/accountsandrds.png differ diff --git a/_images/anonbuckets.png b/_images/anonbuckets.png new file mode 100644 index 0000000000..c9a8732ea2 Binary files /dev/null and b/_images/anonbuckets.png differ diff --git a/_images/customizeview.png b/_images/customizeview.png new file mode 100644 index 0000000000..ce9704b43e Binary files /dev/null and b/_images/customizeview.png differ diff --git a/_images/ec2-inet-open.png b/_images/ec2-inet-open.png new file mode 100644 index 0000000000..9fe37eea65 Binary files /dev/null and b/_images/ec2-inet-open.png differ diff --git a/_images/exposed-internet.png b/_images/exposed-internet.png new file mode 100644 index 0000000000..6aa9ab98b2 Binary files /dev/null and b/_images/exposed-internet.png differ diff --git a/_images/logo-horizontal.png b/_images/logo-horizontal.png new file mode 100644 index 0000000000..341bf463b3 Binary files /dev/null and b/_images/logo-horizontal.png differ diff --git a/_images/selectnode.png b/_images/selectnode.png new file mode 100644 index 0000000000..29dff49e3a Binary files /dev/null and b/_images/selectnode.png differ diff --git a/_images/unencryptedcounts.png b/_images/unencryptedcounts.png new file mode 100644 index 0000000000..7e1d5e53d3 Binary files /dev/null and b/_images/unencryptedcounts.png differ diff --git a/_images/unencryptedinstances.png b/_images/unencryptedinstances.png new file mode 100644 index 0000000000..711db6ce43 Binary files /dev/null and b/_images/unencryptedinstances.png differ diff --git a/_sources/contact.md.txt b/_sources/contact.md.txt new file mode 100644 index 0000000000..f6ee592bca --- /dev/null +++ b/_sources/contact.md.txt @@ -0,0 +1,10 @@ +## Contact + +- Join us on `#cartography` on the [Lyft OSS Slack](https://join.slack.com/t/lyftoss/shared_invite/enQtOTYzODg5OTQwNDE2LTFiYjgwZWM3NTNhMTFkZjc4Y2IxOTI4NTdiNTdhNjQ4M2Q5NTIzMjVjOWI4NmVlNjRiZmU2YzA5NTc3MmFjYTQ). + +## Community Meeting + +Talk to us and see what we're working on at our [monthly community meeting](https://calendar.google.com/calendar/embed?src=lyft.com_p10o6ceuiieq9sqcn1ef61v1io%40group.calendar.google.com&ctz=America%2FLos_Angeles). +- Meeting minutes are [here](https://docs.google.com/document/d/1VyRKmB0dpX185I15BmNJZpfAJ_Ooobwz0U1WIhjDxvw). +- Recorded videos are posted [here](https://www.youtube.com/playlist?list=PLMga2YJvAGzidUWJB_fnG7EHI4wsDDsE1). +- Our current project road map is [here](https://docs.google.com/document/d/18MOsGI-isFvag1fGk718Aht7wQPueWd4SqOI9KapBa8/edit#heading=h.15nsmgmjaaml). diff --git a/_sources/dev/developer-guide.md.txt b/_sources/dev/developer-guide.md.txt new file mode 100644 index 0000000000..279016567e --- /dev/null +++ b/_sources/dev/developer-guide.md.txt @@ -0,0 +1,107 @@ +# Cartography Developer Guide + +## Testing + +_If you'd like to test using Docker and Docker Compose, see [here](testing-with-docker.html)_ + +### Running from source + +1. **Install** + + Follow steps 1 and 2 in [Installation](../install.html#cartography-installation). Ensure that you have JVM 11 installed and Neo4j Community Edition 4.4 is running on your local machine. + +2. **Clone the source code** + + Run `cd {path-where-you-want-your-source-code}`. Get the source code with `git clone git://github.com/lyft/cartography.git` + +3. **Install from source** + + Run `cd cartography` and then `pip install -e .` (yes, actually type the period into the command line) to install Cartography from source. + + ℹ️You may find it beneficial to use Python [virtualenvs](https://packaging.python.org/guides/installing-using-pip-and-virtualenv/) (or the [virutalenvwrapper](https://virtualenvwrapper.readthedocs.io/en/latest/command_ref.html#managing-environments)) so that packages installed via `pip` are easier to manage. + +4. **Run from source** + + After this finishes you should be able to run Cartography from source with `cartography --neo4j-uri `. Any changes to the source code in `{path-where-you-want-your-source-code}/cartography` are now locally testable by running `cartography` from the command line. + +### Manually testing individual intel modules + +After completing the section above, you are now able to manually test intel modules. + +1. **If needed, comment out unnecessary lines** + + See `cartography.intel.aws._sync_one_account()`[here](https://github.com/lyft/cartography/blob/master/cartography/intel/aws/__init__.py). This function syncs different AWS objects with your Neo4j instance. Comment out the lines that you don't want to test for. + + For example, IAM can take a long time to ingest so if you're testing an intel module that doesn't require IAM nodes to already exist in the graph, then you can comment out all of the `iam.sync_*` lines. + +2. Save your changes and run `cartography` from a terminal as you normally would. + +### Automated testing + +1. **Install test requirements** + + `pip install -r test-requirements.txt` + +2. **(OPTIONAL) Setup environment variables for integration tests** + + The integration tests expect Neo4j to be running locally, listening on default ports, with auth disabled: + + To disable auth, edit your `neo4j.conf` file with `dbms.security.auth_enabled=false`. Additional details on [neo4j.com]( https://neo4j.com/docs/operations-manual/current/authentication-authorization/enable/). + + To run the integration tests on a specific Neo4j instance, add the following environment variable: + + `export "NEO4J_URL="` + +3. **Run tests using `make`** + - `make test_lint` can be used to run [pre-commit](https://pre-commit.com) linting against the codebase. We use [pre-commit](https://pre-commit.com) to standardize our linting across our code-base at Lyft. + - `make test_unit` can be used to run the unit test suite. + + ⚠️ Important! The below commands will **DELETE ALL NODES** on your local Neo4j instance as part of our testing procedure. Only run any of the below commands if you are ok with this. ⚠️ + + - `make test_integration` can be used to run the integration test suite. + For more granular testing, you can invoke `pytest` directly: + - `pytest ./tests/integration/cartography/intel/aws/test_iam.py` + - `pytest ./tests/integration/cartography/intel/aws/test_iam.py::test_load_groups` + - `make test` can be used to run all of the above. + +## Implementing custom sync commands + +By default, cartography will try to sync every intel module included as part of the default sync. If you're not using certain intel modules you can create a custom sync script and invoke it using the cartography CLI. For example, if you're only interested in the AWS intel module you can create a sync script, `custom_sync.py`, that looks like this: + +```python +from cartography import cli +from cartography import sync +from cartography.intel import aws +from cartography.intel import create_indexes + +def build_custom_sync(): + s = sync.Sync() + s.add_stages([ + ('create-indexes', create_indexes.run), + ('aws', aws.start_aws_ingestion), + ]) + return s + +def main(argv): + return cli.CLI(build_custom_sync(), prog='cartography').main(argv) + +if __name__ == '__main__': + import sys + sys.exit(main(sys.argv[1:])) +``` + +Which can then be invoked using `python custom_sync.py` and will have all the features of the cartography CLI while only including the intel modules you are specifically interested in using. For example: + +``` +cartography$ python custom_sync.py +INFO:cartography.sync:Starting sync with update tag '1569022981' +INFO:cartography.sync:Starting sync stage 'create-indexes' +INFO:cartography.intel.create_indexes:Creating indexes for cartography node types. +INFO:cartography.sync:Finishing sync stage 'create-indexes' +INFO:cartography.sync:Starting sync stage 'aws' +INFO:botocore.credentials:Found credentials in shared credentials file: ~/.aws/credentials +... +``` + +## How to write a new intel module +See [here](writing-intel-modules.html). diff --git a/_sources/dev/index.rst.txt b/_sources/dev/index.rst.txt new file mode 100644 index 0000000000..05e11df566 --- /dev/null +++ b/_sources/dev/index.rst.txt @@ -0,0 +1,6 @@ +.. toctree:: + + developer-guide + writing-analysis-jobs + writing-intel-modules + testing-with-docker diff --git a/_sources/dev/testing-with-docker.md.txt b/_sources/dev/testing-with-docker.md.txt new file mode 100644 index 0000000000..1a6e4c5baa --- /dev/null +++ b/_sources/dev/testing-with-docker.md.txt @@ -0,0 +1,49 @@ +# Testing with docker + +## Using the included docker-compose support + +### Usage + +```bash +docker build -t lyft/cartography +docker-compose up -d +docker-compose run cartography ... +``` + +### Configuration + +Configuration is possible via the `.compose` directory, which is +git ignored. neo4j config, logs, etc is located at `.compose/neo4j/...` + +Configuration for cartography itself should be passed in through +environment variables, using the docker-compose format `-e VARIABLE -e VARIABLE` + +AWS credentials can be bind mapped in using volumes. TODO: document correct +bind mount format for docker-compose run. + +### Notes + +* On initial start of the compose stack, it's necessary to +change the neo4j user's password through the neo4j UI. +* Neither the docker image, nor the docker-compose file define an +entrypoint, so it's necessary to pass in the command being run. This +also makes it possible to run a custom sync script, rather than only +cartography. + +### Example + +```bash +# Temporarily disable bash command history +set +o history +# See the cartography github configuration intel module docs +export GITHUB_KEY=BASE64ENCODEDKEY +# You need to set this after starting neo4j once, and resetting +# the default neo4j password, which is neo4j +export NEO4j_PASSWORD=... +# Reenable bash command history +set -o history +# Start cartography dependencies +docker-compose up -d +# Run cartography +docker-compose run -e GITHUB_KEY -e NEO4j_PASSWORD cartography cartography --github-config-env-var GITHUB_KEY --neo4j-uri bolt://neo4j:7687 --neo4j-password-env-var NEO4j_PASSWORD --neo4j-user neo4j +``` diff --git a/_sources/dev/writing-analysis-jobs.md.txt b/_sources/dev/writing-analysis-jobs.md.txt new file mode 100644 index 0000000000..a31924994e --- /dev/null +++ b/_sources/dev/writing-analysis-jobs.md.txt @@ -0,0 +1,122 @@ +# How to extend Cartography with Analysis Jobs + +## Overview +In a nutshell, Analysis Jobs let you add your own customizations to Cartography by writing Neo4j queries. This helps you add powerful enhancements to your data without the need to write Python code. + +### The stages +There are 3 stages to a cartography sync. First we create database indexes, next we ingest assets via intel modules, and finally we can run Analysis Jobs on the database (see [cartography.sync.build\_default\_sync()](https://github.com/lyft/cartography/blob/master/cartography/sync.py)). This tutorial focuses on Analysis Jobs. + +### How to run +Each Analysis Job is a JSON file with a list of Neo4j statements which get run in order. To run Analysis Jobs, in your call to `cartography`, set the `--analysis-job-directory` parameter to the folder path of your jobs. Although the order of statements within a single job is preserved, we don't guarantee the order in which jobs are executed. + +## Example job: which of my EC2 instances is accessible to any host on the internet? +The easiest way to learn how to write an Analysis Job is through an example. One of the Analysis Jobs that we've included by default in Cartography's source tree is [cartography/data/jobs/analysis/aws_ec2_asset_exposure.json](https://github.com/lyft/cartography/blob/master/cartography/data/jobs/analysis/aws_ec2_asset_exposure.json). This tutorial covers only the EC2 instance part of that job, but after reading this you should be able to understand the other steps in that file. + +### Our goal +After ingesting all our AWS data, we want to explicitly mark EC2 instances that are accessible to the public internet - a useful thing to know for anyone running an internet service. If any internet-open nodes are found, the job will add an attribute `exposed_internet = True` to the node. This way we can easily query to find the assets later on and take remediation action if needed. + +But how do we make this determination, and how should we structure the job? + +### The logic in plain English +We can use the following facts to tell if an EC2 instance is open to the internet: + +1. The EC2 instance is a member of a Security Group that has an IP Rule applied to it that allows inbound traffic from the 0.0.0.0/0 subnet. +2. The EC2 instance has a network interface that is connected to a Security Group that has an IP Rule applied to it that allows inbound traffic from the 0.0.0.0/0 subnet. + +The graph created by Cartography's sync process already has this information for us; we just need to run a few queries to properly to mark it with `exposed_internet = True`. This example is complex but we hope that this exposes enough Neo4j concepts to help you write your own queries. + +### Translating the plain-English logic into Neo4j's Cypher syntax +We can take the ideas above and use Cypher's declarative syntax to "sketch" out this graph path. + +1. _The EC2 instance is a member of a Security Group that has an IP Rule applied to it that allows inbound traffic from the 0.0.0.0/0 subnet._ + + In Cypher, this is + + ``` + MATCH + (:IpRange{id: '0.0.0.0/0'})-[:MEMBER_OF_IP_RULE]->(:IpPermissionInbound) + -[:MEMBER_OF_EC2_SECURITY_GROUP]->(group:EC2SecurityGroup) + <-[:MEMBER_OF_EC2_SECURITY_GROUP]-(instance:EC2Instance) + + SET instance.exposed_internet = true, + instance.exposed_internet_type = coalesce(instance.exposed_internet_type , []) + 'direct'; + ``` + + In the `SET` clause we add `exposed_internet = True` to the instance. We also add a field for `exposed_internet_type` to denote what type of internet exposure has occurred here. You can read the [documentation for `coalesce`](https://neo4j.com/docs/cypher-manual/current/functions/scalar/#functions-coalesce), but in English this last part says "add `direct` to the list of ways this instance is exposed to the internet". + +2. _The EC2 instance has a network interface that is connected to a Security Group that has an IP Rule applied to it that allows inbound traffic from the 0.0.0.0/0 subnet._ + + This is the same as the previous query except for the final line: + + ``` + MATCH + (:IpRange{id: '0.0.0.0/0'})-[:MEMBER_OF_IP_RULE]->(:IpPermissionInbound) + -[:MEMBER_OF_EC2_SECURITY_GROUP]->(group:EC2SecurityGroup) + <-[:NETWORK_INTERFACE*..2]-(instance:EC2Instance) + + SET instance.exposed_internet = true, + instance.exposed_internet_type = coalesce(instance.exposed_internet_type , []) + 'direct'; + ``` + + The `*..2` operator means "within 2 hops". We use this here as a shortcut because there are a few more relationships between NetworkInterfaces and EC2SecurityGroups that we can skip over. + +Finally, notice that (1) and (2) are similar enough that we can actually merge them like this: + +``` +MATCH +(:IpRange{id: '0.0.0.0/0'})-[:MEMBER_OF_IP_RULE]->(:IpPermissionInbound) +-[:MEMBER_OF_EC2_SECURITY_GROUP]->(group:EC2SecurityGroup) +<-[:MEMBER_OF_EC2_SECURITY_GROUP|NETWORK_INTERFACE*..2]-(instance:EC2Instance) + +SET instance.exposed_internet = true, + instance.exposed_internet_type = coalesce(instance.exposed_internet_type , []) + 'direct'; +``` + +Kinda neat, right? + +### The skeleton of an Analysis Job +Now that we know what we want to do on a sync, how should we structure the Analysis Job? Here is the basic skeleton that we recommend. + +#### Clean up first, then update +In general, the first statement(s) should be a "clean-up phase" that removes custom attributes or relationships that you may have added in a previous run. This ensures that whatever labels you add on this current run will be up to date and not stale. Next, the statements after the clean-up phase will perform the matching and attribute updates as described in the previous section. + +**Here's our final result:** + +``` +{ + "name": "AWS asset internet exposure", + "statements": [ + { + "__comment": "This is a clean-up statement to remove custom attributes", + "query": "MATCH (n) + WHERE n.exposed_internet IS NOT NULL + AND labels(n) IN ['AutoScalingGroup', 'EC2Instance', 'LoadBalancer'] + WITH n LIMIT $LIMIT_SIZE + REMOVE n.exposed_internet, n.exposed_internet_type + RETURN COUNT(*) as TotalCompleted", + "iterative": true, + "iterationsize": 1000 + }, + { + "__comment__": "This is our analysis logic as described in the section above", + "query": MATCH (:IpRange{id: '0.0.0.0/0'})-[:MEMBER_OF_IP_RULE]->(:IpPermissionInbound) + -[:MEMBER_OF_EC2_SECURITY_GROUP]->(group:EC2SecurityGroup) + <-[:MEMBER_OF_EC2_SECURITY_GROUP|NETWORK_INTERFACE*..2]-(instance:EC2Instance) + + SET instance.exposed_internet = true, + instance.exposed_internet_type = coalesce(instance.exposed_internet_type , []) + 'direct';, + "iterative": true, + "iterationsize": 100 + } + ] +} +``` + +Setting a statement as `iterative: true` means that we will run this query on `#{iterationsize}` entries at a time. This can be helpful for queries that return large numbers of records so that Neo4j doesn't get too angry. + +Now we can enjoy the fruits of our labor and query for internet exposure: + +![internet-exposure-query](../images/exposed-internet.png) + +## Recap +As shown, you create an Analysis Job by putting together a bunch of `statements` together (which are essentially Neo4j queries). In general, each job should first clean up the custom attributes added by a previous run, and then it can perform the match and update steps to add the custom attributes back again. This ensures that your data is up to date. diff --git a/_sources/dev/writing-intel-modules.md.txt b/_sources/dev/writing-intel-modules.md.txt new file mode 100644 index 0000000000..a588a08cbb --- /dev/null +++ b/_sources/dev/writing-intel-modules.md.txt @@ -0,0 +1,342 @@ +# How to write a new intel module + +If you want to add a new data type to Cartography, this is the guide for you. We look forward to receiving your PR! + +## Before getting started... + +Read through and follow the setup steps in [the Cartography developer guide](developer-guide.html). Learn the basics of +running, testing, and linting your code there. + +## The fast way + +To get started coding without reading this doc, just copy the structure of our [AWS EMR module](https://github.com/lyft/cartography/blob/master/cartography/intel/aws/emr.py) and use it as an example. For a longer written explanation of the "how" and "why", read on. + +## Configuration and credential management + +### Supplying credentials and arguments to your module + +If you need to supply an API key or other credential to your Cartography module, we recommend adding a CLI argument. An example of this can be seen [in our Okta module](https://github.com/lyft/cartography/blob/811990606c22a42791d213c7ca845b15f87e47f1/cartography/cli.py#L136) where we require the user to specify the name of an environment variable containing their Okta API key. This credential will then be bound to Cartography's [Config object](https://github.com/lyft/cartography/blob/811990606c22a42791d213c7ca845b15f87e47f1/cartography/config.py#L3) which is present in all modules. You can specify different arguments from the commandline for your module via the Config object. + +### An important note on validating your commandline args + +Note that it is your module's responsibility to validate arguments that you introduce. For example with the Okta module, we [validate](https://github.com/lyft/cartography/blob/811990606c22a42791d213c7ca845b15f87e47f1/cartography/intel/okta/__init__.py#L37) that `config.okta_api_key` has been defined before attempting to continue. + +## Sync = Get, Transform, Load, Cleanup + +A cartography intel module consists of one `sync` function. `sync` should call `get`, then `load`, and finally `cleanup`. + +### Get + +The `get` function [returns data as a list of dicts](https://github.com/lyft/cartography/blob/8d60311a10156cd8aa16de7e1fe3e109cc3eca0f/cartography/intel/gcp/compute.py#L98) +from a resource provider API, which is GCP in this particular example. + +`get` should be "dumb" in the sense that it should not handle retry logic or data +manipulation. It should also raise an exception if it's not able to complete successfully. + +### Transform + +The `transform` function [manipulates the list of dicts](https://github.com/lyft/cartography/blob/8d60311a10156cd8aa16de7e1fe3e109cc3eca0f/cartography/intel/gcp/compute.py#L193) +to make it easier to ingest to the graph. `transform` functions are sometimes omitted when a module author decides that the output from the `get` is already in the shape that they need. + +We have some best practices on handling transforms: + +#### Handling required versus optional fields + +We should directly access dicts in cases where not having the data should cause a sync to fail. +For example, if we are transforming AWS data, we definitely need an AWS object's ARN field because it uniquely +identifies the object. Therefore, we should access an object's ARN using `data['arn']` as opposed to +using `data.get('arn')` (the former will raise a `KeyError` if `arn` does not exist and the latter will just return +`None` without an exception). + +We _want_ the sync to fail if an important field is not present in our data. The idea here is that +it is better to fail a sync than to add malformed data. + +On the other hand, we should use `data.get('SomeField')` if `SomeField` is something optional that can afford to be +`None`. + +For the sake of consistency, if a field does not exist, set it to `None` and not `""`. + +### Load + +[As seen in our AWS EMR example](https://github.com/lyft/cartography/blob/e6ada9a1a741b83a34c1c3207515a1863debeeb9/cartography/intel/aws/emr.py#L113-L132), the `load` function ingests a list of dicts to Neo4j by calling [cartography.client.core.tx.load()](https://github.com/lyft/cartography/blob/e6ada9a1a741b83a34c1c3207515a1863debeeb9/cartography/client/core/tx.py#L191-L212): +```python +def load_emr_clusters( + neo4j_session: neo4j.Session, + cluster_data: List[Dict[str, Any]], + region: str, + current_aws_account_id: str, + aws_update_tag: int, +) -> None: + logger.info(f"Loading EMR {len(cluster_data)} clusters for region '{region}' into graph.") + load( + neo4j_session, + EMRClusterSchema(), + cluster_data, + lastupdated=aws_update_tag, + Region=region, + AWS_ID=current_aws_account_id, + ) + +``` + + +#### Defining a node + +As an example of a `CartographyNodeSchema`, you can view our [EMRClusterSchema code](https://github.com/lyft/cartography/blob/e6ada9a1a741b83a34c1c3207515a1863debeeb9/cartography/intel/aws/emr.py#L106-L110): + +```python +@dataclass(frozen=True) +class EMRClusterSchema(CartographyNodeSchema): + label: str = 'EMRCluster' # The label of the node + properties: EMRClusterNodeProperties = EMRClusterNodeProperties() # An object representing all properties on the EMR Cluster node + sub_resource_relationship: EMRClusterToAWSAccount = EMRClusterToAWSAccount() +``` + +An `EMRClusterSchema` object inherits from the `CartographyNodeSchema` class and contains a node label, properties, and connection to its [sub-resource](https://github.com/lyft/cartography/blob/e6ada9a1a741b83a34c1c3207515a1863debeeb9/cartography/graph/model.py#L216-L228): an `AWSAccount`. + +Note that the typehints are necessary for Python dataclasses to work properly. + + +#### Defining node properties + +Here's our [EMRClusterNodeProperties code](https://github.com/lyft/cartography/blob/e6ada9a1a741b83a34c1c3207515a1863debeeb9/cartography/intel/aws/emr.py#L106-L110): + +```python +@dataclass(frozen=True) +class EMRClusterNodeProperties(CartographyNodeProperties): + arn: PropertyRef = PropertyRef('ClusterArn', extra_index=True) + firstseen: PropertyRef = PropertyRef('firstseen') + id: PropertyRef = PropertyRef('Id') + # ... + lastupdated: PropertyRef = PropertyRef('lastupdated', set_in_kwargs=True) + region: PropertyRef = PropertyRef('Region', set_in_kwargs=True) + security_configuration: PropertyRef = PropertyRef('SecurityConfiguration') +``` + +A `CartographyNodeProperties` object consists of [`PropertyRef`](https://github.com/lyft/cartography/blob/e6ada9a1a741b83a34c1c3207515a1863debeeb9/cartography/graph/model.py#L37) objects. `PropertyRefs` tell `querybuilder.build_ingestion_query()` where to find appropriate values for each field from the list of dicts. + +For example, `id: PropertyRef = PropertyRef('Id')` above tells the querybuilder to set a field called `id` on the `EMRCluster` node using the value located at key `'id'` on each dict in the list. + +As another example, `region: PropertyRef = PropertyRef('Region', set_in_kwargs=True)` tells the querybuilder to set a field called `region` on the `EMRCluster` node using a keyword argument called `Region` supplied to `cartography.client.core.tx.load()`. `set_in_kwargs=True` is useful in cases where we want every object loaded by a single call to `load()` to have the same value for a given attribute. + +##### Node property indexes +Cartography uses its data model to automatically create indexes for +- node properties that uniquely identify the node (e.g. `id`) +- node properties are used to connect a node to other nodes (i.e. they are used as part of a `TargetNodeMatcher` on a `CartographyRelSchema`.) +- a node's `lastupdated` field -- this is used to enable faster cleanup jobs + +As seen in the above definition for `EMRClusterNodeProperties.arn`, you can also explicitly specify additional indexes for fields that you expect to be queried on by providing `extra_index=True` to the `PropertyRef` constructor: + +```python +class EMRClusterNodeProperties(CartographyNodeProperties): + # ... + arn: PropertyRef = PropertyRef('ClusterArn', extra_index=True) +``` + +Index creation is idempotent (we only create them if they don't exist). + +See [below](#indexescypher) for more information on indexes. + + +#### Defining relationships + +Relationships can be defined on `CartographyNodeSchema` on either their [`sub_resource_relationship`](https://github.com/lyft/cartography/blob/e6ada9a1a741b83a34c1c3207515a1863debeeb9/cartography/graph/model.py#L216-L228) field or their [`other_relationships`](https://github.com/lyft/cartography/blob/e6ada9a1a741b83a34c1c3207515a1863debeeb9/cartography/graph/model.py#L230-L237) field (you can find an example of `other_relationships` [here in our test data](https://github.com/lyft/cartography/blob/4bfafe0e0c205909d119cc7f0bae84b9f6944bdd/tests/data/graph/querybuilder/sample_models/interesting_asset.py#L89-L94)). + +As seen above, an `EMRClusterSchema` only has a single relationship defined: an [`EMRClusterToAWSAccount`](https://github.com/lyft/cartography/blob/e6ada9a1a741b83a34c1c3207515a1863debeeb9/cartography/intel/aws/emr.py#L94-L103): + +```python +@dataclass(frozen=True) +# (:EMRCluster)<-[:RESOURCE]-(:AWSAccount) +class EMRClusterToAWSAccount(CartographyRelSchema): + target_node_label: str = 'AWSAccount' # (1) + target_node_matcher: TargetNodeMatcher = make_target_node_matcher( # (2) + {'id': PropertyRef('AccountId', set_in_kwargs=True)}, + ) + direction: LinkDirection = LinkDirection.INWARD # (3) + rel_label: str = "RESOURCE" # (4) + properties: EMRClusterToAwsAccountRelProperties = EMRClusterToAwsAccountRelProperties() # (5) +``` + +This class is best described by explaining how it is processed: `build_ingestion_query()` will traverse the `EMRClusterSchema` to its `sub_resource_relationship` field and find the above `EMRClusterToAWSAccount` object. With this information, we know to +- draw a relationship to an `AWSAccount` node (1) using the label "`RESOURCE`" (4) +- by matching on the AWSAccount's "`id`" field" (2) +- where the relationship [directionality](https://github.com/lyft/cartography/blob/e6ada9a1a741b83a34c1c3207515a1863debeeb9/cartography/graph/model.py#L12-L34) is pointed _inward_ toward the EMRCluster (3) +- making sure to define a set of properties for the relationship (5). The [full example RelProperties](https://github.com/lyft/cartography/blob/e6ada9a1a741b83a34c1c3207515a1863debeeb9/cartography/intel/aws/emr.py#L89-L91) is very short: + +```python +@dataclass(frozen=True) +class EMRClusterToAwsAccountRelProperties(CartographyRelProperties): + lastupdated: PropertyRef = PropertyRef('lastupdated', set_in_kwargs=True) +``` + +#### The result + +And those are all the objects necessary for this example! The resulting query will look something like this: + +```cypher +UNWIND $DictList AS item + MERGE (i:EMRCluster{id: item.Id}) + ON CREATE SET i.firstseen = timestamp() + SET + i.lastupdated = $lastupdated, + i.arn = item.ClusterArn + // ... + + WITH i, item + CALL { + WITH i, item + + OPTIONAL MATCH (j:AWSAccount{id: $AccountId}) + WITH i, item, j WHERE j IS NOT NULL + MERGE (i)<-[r:RESOURCE]-(j) + ON CREATE SET r.firstseen = timestamp() + SET + r.lastupdated = $lastupdated + } +``` + +And that's basically all you need to know to understand how to define your own nodes and relationships using cartography's data objects. For more information, you can view the [object model API documentation](https://github.com/lyft/cartography/blob/master/cartography/graph/model.py) as a reference. + +### Additional concepts + +This section explains cartography general patterns, conventions, and design decisions. + +#### cartography's `update_tag`: + +`cartography`'s global [config object carries around an `update_tag` property](https://github.com/lyft/cartography/blob/8d60311a10156cd8aa16de7e1fe3e109cc3eca0f/cartography/cli.py#L91-L98) +which is a tag/label associated with the current sync. +Cartography's CLI code [sets this to a Unix timestamp of when the CLI was run](https://github.com/lyft/cartography/blob/8d60311a10156cd8aa16de7e1fe3e109cc3eca0f/cartography/sync.py#L131-L134). + +All `cartography` intel modules set the `lastupdated` property on all nodes and all relationships to this `update_tag`. + + +#### All nodes need these fields + +- `id` - an ID should be a string that uniquely identifies the node. In AWS, this is usually an + ARN. In GCP, this is usually a partial URI. + + If possible, we should use API-provided fields for IDs and not create our own. + In some cases though this is unavoidable - + see [GCPNetworkTag](https://github.com/lyft/cartography/blob/8d60311a10156cd8aa16de7e1fe3e109cc3eca0f/docs/schema/gcp.md#gcpnetworktag). + + When setting an `id`, ensure that you also include the field name that it came from. For example, since we've + decided to use `partial_uri`s as an id for a GCPVpc, we should include both `partial_uri` _and_ `id` on the node. + This way, a user can tell what fields were used to derive the `id`. This is accomplished [here](https://github.com/lyft/cartography/blob/8d60311a10156cd8aa16de7e1fe3e109cc3eca0f/cartography/intel/gcp/compute.py#L455-L457) + +- `lastupdated` - See [below](#lastupdated-and-firstseen) on how this gets set automatically. +- `firstseen` - See [below](#lastupdated-and-firstseen) on how this gets set automatically. + +#### All relationships need these fields + +Cartography currently does not create indexes on relationships, so in most cases we should keep relationships lightweight with only these two fields: + +- `lastupdated` - See [below](#lastupdated-and-firstseen) on how this gets set automatically. +- `firstseen` - See [below](#lastupdated-and-firstseen) on how this gets set automatically. + +#### Run queries only on indexed fields for best performance + +In this older example of ingesting GCP VPCs, we connect VPCs with GCPProjects +[based on GCPProject `id`s and GCPVpc `id`s](https://github.com/lyft/cartography/blob/8d60311a10156cd8aa16de7e1fe3e109cc3eca0f/cartography/intel/gcp/compute.py#L451). +`id`s are indexed, as seen [here](https://github.com/lyft/cartography/blob/8d60311a10156cd8aa16de7e1fe3e109cc3eca0f/cartography/data/indexes.cypher#L45) +and [here](https://github.com/lyft/cartography/blob/8d60311a10156cd8aa16de7e1fe3e109cc3eca0f/cartography/data/indexes.cypher#L42). +All of these queries use indexes for faster lookup. + +#### indexes.cypher + +Older intel modules define indexes in [indexes.cypher](https://github.com/lyft/cartography/blob/8d60311a10156cd8aa16de7e1fe3e109cc3eca0f/cartography/data/indexes.cypher). +By using CartographyNodeSchema and CartographyRelSchema objects, indexes are automatically created so you don't need to update this file! + + +#### lastupdated and firstseen + +On every cartography node and relationship, we set the `lastupdated` field to the `UPDATE_TAG` and `firstseen` field to `timestamp()` (a built-in Neo4j function equivalent to epoch time in milliseconds). This is automatically handled by the cartography object model. + +### Cleanup + +We have just added new nodes and relationships to the graph, and we have also updated previously-added ones +by using `MERGE`. We now need to delete nodes and relationships that no longer exist, and we do this by removing +all nodes and relationships that have `lastupdated` NOT set to the `update_tag` of this current run. + +By using Cartography schema objects, a cleanup function is [trivial to write](https://github.com/lyft/cartography/blob/82e1dd0e851475381ac8f2a9a08027d67ec1d772/cartography/intel/aws/emr.py#L77-L80): + +```python +def cleanup(neo4j_session: neo4j.Session, common_job_parameters: Dict) -> None: + logger.debug("Running EMR cleanup job.") + cleanup_job = GraphJob.from_node_schema(EMRClusterSchema(), common_job_parameters) + cleanup_job.run(neo4j_session) +``` + +Older intel modules still do this process with hand-written cleanup jobs that work like this: + +- Delete all old nodes + + You can see this in our [GCP VPCs example](https://github.com/lyft/cartography/blob/8d60311a10156cd8aa16de7e1fe3e109cc3eca0f/cartography/data/jobs/cleanup/gcp_compute_vpc_cleanup.json#L4). + We run `DETACH DELETE` to delete an old node and disconnect it from all other nodes. + + - Delete all old relationships + + You can see this in the GCP VPC example [here](https://github.com/lyft/cartography/blob/8d60311a10156cd8aa16de7e1fe3e109cc3eca0f/cartography/data/jobs/cleanup/gcp_compute_vpc_cleanup.json#L10) + and [here](https://github.com/lyft/cartography/blob/8d60311a10156cd8aa16de7e1fe3e109cc3eca0f/cartography/data/jobs/cleanup/gcp_compute_vpc_cleanup.json#L16). + + - Q: We just `DETACH DELETE`'d the node. Why do we need to delete the relationships too? + + - A: There are cases where the node may continue to exist but the relationships between it and other nodes have changed. + Explicitly deleting stale relationships accounts for this case. + See this [short discussion](https://github.com/lyft/cartography/pull/124/files#r312277725). + +## Error handling principles + +- Don't catch the base Exception class when error handling because it makes problems difficult to trace. + +- Do catch the narrowest possible class of exception. + +- Only catch exceptions when your code can resolve the issue. Otherwise, allow exceptions to bubble up. + +## Schema + +- Update the [schema](https://github.com/lyft/cartography/tree/8d60311a10156cd8aa16de7e1fe3e109cc3eca0f/docs/schema) +with every change! + +## Making tests + +- Before making tests, read through and follow the setup steps in [the Cartography developer guide](developer-guide.html). + +- Add fake data for testing at `tests/data`. We can see +the GCP VPC example here: https://github.com/lyft/cartography/blob/0652c2b6dede589e805156925353bffc72da6c2b/tests/data/gcp/compute.py#L2. + +- Add unit tests to `tests/unit/cartography/intel`. See this [example](https://github.com/lyft/cartography/blob/828ed600f2b14adae9d0b78ef82de0acaf24b86a/tests/unit/cartography/intel/gcp/test_compute.py). + These tests ensure that `transform*` manipulates the data in expected ways. + +- Add integration tests to `tests/integration/cartography/intel`. See this [example](https://github.com/lyft/cartography/blob/828ed600f2b14adae9d0b78ef82de0acaf24b86a/tests/integration/cartography/intel/gcp/test_compute.py). + These tests assume that you have neo4j running at localhost:7687 with no password, and ensure that nodes loaded to the + graph match your mock data. + +## Other + +- We prefer and will accept PRs which incrementally add information from a particular data source. Incomplete +representations are OK provided they are consistent over time. For example, we don't sync 100% of AWS resources but the +resources that exist in the graph don't change across syncs. + +- Each intel module offers its own view of the graph + + ℹ️ This best practice is a little more less precise, so if you've gotten to this point and you need clarification, just + submit your PR and ask us. + + As much as possible, each intel module should ingest data without assuming that a different module will ingest the + same data. Explained another way, each module should "offer its own perspective" on the data. We believe doing this + gives us a more complete graph. Below are some key guidelines clarifying and justifying this design choice. + + - Use `MERGE` when connecting one node type to another node type. + + - It is possible (and encouraged) for more than one intel module to modify the same node type. + + For example, when we [connect RDS instances to their associated EC2 security + groups](https://github.com/lyft/cartography/blob/6e060389fbeb14f4ccc3e58005230129f1c6962f/cartography/intel/aws/rds.py#L188) + there are actually two different intel modules that retrieve EC2 security group data: the [RDS module](https://github.com/lyft/cartography/blob/6e060389fbeb14f4ccc3e58005230129f1c6962f/cartography/intel/aws/rds.py#L13) + returns [partial group data](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DBSecurityGroupMembership.html), + and the EC2 module returns more complete data as it calls APIs specific for [retrieving and loading security groups](https://github.com/lyft/cartography/blob/6e060389fbeb14f4ccc3e58005230129f1c6962f/cartography/intel/aws/ec2.py#L166). + Because both the RDS and EC2 modules `MERGE` on a unique ID, we don't need to worry about + creating duplicate nodes in the graph. + + Another less obvious benefit of using `MERGE` across more than one intel module to connect nodes in this way is that + in many cases, we've seen an intel module discover nodes that another module was not aware of! diff --git a/_sources/index.rst.txt b/_sources/index.rst.txt new file mode 100644 index 0000000000..7035275281 --- /dev/null +++ b/_sources/index.rst.txt @@ -0,0 +1,32 @@ +.. mdinclude:: info.md + +.. toctree:: + :hidden: + + info + +.. toctree:: + :caption: Basic Use + :hidden: + + install + usage/index + ops + +.. toctree:: + :caption: Intel Modules + :hidden: + + modules/index + +.. toctree:: + :caption: Development Docs + :hidden: + + dev/index + +.. toctree:: + :caption: Get In Touch + :hidden: + + contact diff --git a/_sources/info.md.txt b/_sources/info.md.txt new file mode 100644 index 0000000000..0b8b625728 --- /dev/null +++ b/_sources/info.md.txt @@ -0,0 +1,17 @@ +![logo](images/logo-horizontal.png) + +# What is Cartography? + +Cartography is a Python tool that consolidates infrastructure assets and the relationships between them in an intuitive graph view powered by a [Neo4j](https://www.neo4j.com) database. + +![example](images/accountsandrds.png) + +# Why Cartography? + +Cartography aims to enable a broad set of exploration and automation scenarios. It is particularly good at exposing otherwise hidden dependency relationships between your service's assets so that you may validate assumptions about security risks. + +Service owners can generate asset reports, Red Teamers can discover attack paths, and Blue Teamers can identify areas for security improvement. All can benefit from using the graph for manual exploration through a web frontend interface, or in an automated fashion by calling the APIs. + +Cartography is not the only [security](https://github.com/dowjones/hammer) [graph](https://github.com/BloodHoundAD/BloodHound) [tool](https://github.com/Netflix/security_monkey) [out](https://github.com/vysecurity/ANGRYPUPPY) [there](https://github.com/duo-labs/cloudmapper), but it differentiates itself by being fully-featured yet generic and [extensible](dev/writing-analysis-jobs.html) enough to help make anyone better understand their risk exposure, regardless of what platforms they use. Rather than being focused on one core scenario or attack vector like the other linked tools, Cartography focuses on flexibility and exploration. + +You can learn more about the story behind Cartography in our [presentation at BSidesSF 2019](https://www.youtube.com/watch?v=ZukUmZSKSek). diff --git a/_sources/install.md.txt b/_sources/install.md.txt new file mode 100644 index 0000000000..0e3d8ffd69 --- /dev/null +++ b/_sources/install.md.txt @@ -0,0 +1,59 @@ +# Cartography Installation + +.. _cartography-installation: + +Time to set up the server that will run Cartography. Cartography _should_ work on both Linux and Windows servers, but bear in mind we've only tested it in Linux so far. Cartography supports Python 3.8. Older versions of Python may work but are not explicitly supported. + +1. **Run the Neo4j graph database version 4.x** on your server. + + ⚠️ Neo4j 5.x will probably work but Cartography does not explicitly support it yet. + + 1. If you prefer **Docker**, follow the Neo4j Docker [official docs](https://github.com/neo4j/docker-neo4j) to run a version 4.x container. + + - If you are using an ARM-based machine like an M1 Mac, you should use an ARM image otherwise performance will be very slow - Neo4j keeps ARM builds [here](https://hub.docker.com/r/arm64v8/neo4j/). + + - If you're just playing around, you can specify the `--env=NEO4J_AUTH=none` argument to your `docker` command to run a Neo4j container without authentication. + + 1. Else if you prefer a **manual install**, + + 1. Neo4j requires a JVM (JDK/JRE 11 or higher) to be installed. One option is to install [Amazon Coretto 11](https://docs.aws.amazon.com/corretto/latest/corretto-11-ug/what-is-corretto-11.html). + + ⚠️ Make sure you have `JAVA_HOME` environment variable set. The following works for Mac OS: `export JAVA_HOME=$(/usr/libexec/java_home)` + + 1. Go to the [Neo4j download page](https://neo4j.com/download-center/#community), and download Neo4j Community Edition 4.4.\*. If you prefer Docker, you can view Neo4j's instructions [here]. + + 1. [Install](https://neo4j.com/docs/operations-manual/current/installation/) Neo4j on the server you will run Cartography on. + + ⚠️ For local testing, you might want to turn off authentication via property `dbms.security.auth_enabled` in file /NEO4J_PATH/conf/neo4j.conf + +4. Configure your data sources. See the configuration section of each relevant intel module for more details. + +5. **Get and run Cartography** + + 1. Run `pip install cartography` to install our code. + + 1. Finally, to sync your data: + + - For one account using the `default` profile defined in your AWS config file, run + + ``` + cartography --neo4j-uri + ``` + + - Or for a specific account defined as a separate profile in your AWS config file, set the `AWS_PROFILE` environment variable, for example + + ``` + AWS_PROFILE=other-profile cartography --neo4j-uri + ``` + + - For more than one AWS account, run + + ``` + AWS_CONFIG_FILE=/path/to/your/aws/config cartography --neo4j-uri --aws-sync-all-profiles + ``` + + You can view a full list of Cartography's CLI arguments by running `cartography --help` + + The sync will pull data from your configured accounts and ingest data to Neo4j! This process might take a long time if your account has a lot of assets. + + 1. See our [Operations Guide](ops.html) for tips on running Cartography in production. diff --git a/_sources/modules/_cartography-metadata/schema.md.txt b/_sources/modules/_cartography-metadata/schema.md.txt new file mode 100644 index 0000000000..878d8268df --- /dev/null +++ b/_sources/modules/_cartography-metadata/schema.md.txt @@ -0,0 +1,18 @@ +## Cartography metadata schema + +.. _metadata_schema: + +Some Cartography sync jobs write nodes to convey information about the job itself. See https://github.com/lyft/cartography/issues/758 for more background on this. + +### SyncMetadata:ModuleSyncMetadata + +This is a node to represent metadata about the sync job of a particular module. Its existence indicates that a particular sync job did happen. +The 'types' used here should be actual node labels. For example, if we did sync a particular AWSAccount's S3Buckets, +the `grouptype` is 'AWSAccount', the `groupid` is the particular account's `id`, and the `syncedtype` is 'S3Bucket'. + +| Field | Description | Source| +|-------|-------------|------| +|**id**|`{group_type}_{group_id}_{synced_type}`|util.py| +|grouptype| The parent module's type |util.py| +|groupid|The parent module's id|util.py| +|syncedtype|The sub-module's type|util.py| diff --git a/_sources/modules/aws/config.md.txt b/_sources/modules/aws/config.md.txt new file mode 100644 index 0000000000..7a02c5e59b --- /dev/null +++ b/_sources/modules/aws/config.md.txt @@ -0,0 +1,92 @@ +## AWS Configuration + +.. _aws_config: + +Follow these steps to analyze AWS assets with Cartography. + +### Single AWS Account Setup + +1. Set up an AWS identity (user, group, or role) for Cartography to use. Ensure that this identity has the built-in AWS [SecurityAudit policy](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_job-functions.html#jf_security-auditor) (arn:aws:iam::aws:policy/SecurityAudit) attached. This policy grants access to read security config metadata. The SecurityAudit policy does not yet containe permissions for `inspector2`, so you will also need the [AmazonInspector2ReadOnlyAccess policy](https://docs.aws.amazon.com/inspector/latest/user/security-iam-awsmanpol.html#security-iam-awsmanpol-AmazonInspector2ReadOnlyAccess). +1. Set up AWS credentials to this identity on your server, using a `config` and `credential` file. For details, see AWS' [official guide](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html). +1. [Optional] Configure AWS Retry settings using `AWS_MAX_ATTEMPTS` and `AWS_RETRY_MODE` environment variables. This helps in API Rate Limit throttling and TooManyRequestException related errors. For details, see AWS' [official guide](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/configuration.html#using-environment-variables). + + +### Multiple AWS Account Setup + +There are many ways to allow Cartography to pull from more than one AWS account. We can't cover all of them, but we _can_ show you the way we have things set up at Lyft. In this scenario we will assume that you are going to run Cartography on an EC2 instance. + +1. Pick one of your AWS accounts to be the "**Hub**" account. This Hub account will pull data from all of your other accounts - we'll call those "**Spoke**" accounts. + +2. **Set up the IAM roles**: Create an IAM role named `cartography-read-only` on _all_ of your accounts. Configure the role on all accounts as follows: + 1. Attach the built-in AWS [SecurityAudit IAM policy](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_job-functions.html#jf_security-auditor) (arn:aws:iam::aws:policy/SecurityAudit) to the role. This grants access to read security config metadata. + 2. Set up a trust relationship so that the Spoke accounts will allow the Hub account to assume the `cartography-read-only` role. The resulting trust relationship should look something like this: + + ``` + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "AWS": "arn:aws:iam:::root" + }, + "Action": "sts:AssumeRole" + } + ] + } + ``` + 3. Allow a role in the Hub account to **assume the `cartography-read-only` role** on your Spoke account(s). + + - On the Hub account, create a role called `cartography-service`. + - On this new `cartography-service` role, add an inline policy with the following JSON: + + ``` + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Resource": "arn:aws:iam::*:role/cartography-read-only", + "Action": "sts:AssumeRole" + }, + { + "Effect": "Allow", + "Action": "ec2:DescribeRegions", + "Resource": "*" + } + ] + } + ``` + + This allows the Hub role to assume the `cartography-read-only` role on your Spoke accounts and to fetch all the different regions used by the Spoke accounts. + + - When prompted to name the policy, you can name it anything you want - perhaps `CartographyAssumeRolePolicy`. + +3. **Set up your EC2 instance to correctly access these AWS identities** + + 1. Attach the `cartography-service` role to the EC2 instance that you will run Cartography on. You can do this by following [these official AWS steps](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html#attach-iam-role). + + 2. Ensure that the `[default]` profile in your `AWS_CONFIG_FILE` file (default `~/.aws/config` in Linux, and `%UserProfile%\.aws\config` in Windows) looks like this: + + [default] + region= + output=json + + 3. Add a profile for each AWS account you want Cartography to sync with to your `AWS_CONFIG_FILE`. It will look something like this: + + ``` + [profile accountname1] + role_arn = arn:aws:iam:::role/cartography-read-only + region=us-east-1 + output=json + credential_source = Ec2InstanceMetadata + + [profile accountname2] + role_arn = arn:aws:iam:::role/cartography-read-only + region=us-west-1 + output=json + credential_source = Ec2InstanceMetadata + + ... etc ... + ``` +1. [Optional] Configure AWS Retry settings using `AWS_MAX_ATTEMPTS` and `AWS_RETRY_MODE` environment variables. This helps in API Rate Limit throttling and TooManyRequestException related errors. For details, see AWS' [official guide](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/configuration.html#using-environment-variables). diff --git a/_sources/modules/aws/index.rst.txt b/_sources/modules/aws/index.rst.txt new file mode 100644 index 0000000000..e88e6e24bb --- /dev/null +++ b/_sources/modules/aws/index.rst.txt @@ -0,0 +1,29 @@ +Amazon Web Services (AWS) +========================= + +The AWS module has the following coverage: + +* API Gateway - Rest APIs, Stages, Certificates, Resources +* Config - Configuration Recorders, Delivery Channels, Config Rules +* EC2 - Autoscaling groups, Elastic IPs, AMIs, Instances, Internet Gateways, SSH Key Pairs, Launch Templates, Launch Config, Load Balancers (V1 and V2), Network Interfaces, Reserved Instances, Security Groups, EBS Volumes, EBS Snapshots, Subnets, Trusted Gateway, VPC, VPC Peerings +* Elasticsearch - Domains +* Elastic Kubernetes Service - Clusters +* DynamoDB - Tables, Global Secondary Indexes +* IAM - Users, User Access Keys, Roles, Groups, Group Membership, Principals, Policies (managed and inline), Assume Role Relationships +* KMS - Keys, Key Policy, Grants, Aliases +* Lambda - Functions, Aliases, Source Mappings, Layers +* RDS - Clusters, Instances, Subnet Groups, Security Groups, Read Replicas +* Redshift - Clusters +* Route53 - Records, Zones +* S3 - Buckets, Bucket Policy, ACLs +* Secrets Manager - Secrets +* Security Hub - Basic Hub Details +* SQS - Queues, Dead Letter Queues +* STS +* Tags - Tag support for the supported resources, if supported by the resource groups tagging API + +.. toctree:: + :hidden: + :glob: + + * diff --git a/_sources/modules/aws/permissions-mapping.md.txt b/_sources/modules/aws/permissions-mapping.md.txt new file mode 100644 index 0000000000..c439c1cde8 --- /dev/null +++ b/_sources/modules/aws/permissions-mapping.md.txt @@ -0,0 +1,33 @@ +## Permissions Mapping + +### How to use Permissions Mapping +An AWSPrincipal contains AWSPolicies which contain AWSPolicyStatements which grant permission to resources. Cartography can map in permission relationships between IAM Pricipals (AWSPrincipal nodes) and the resources they have permission to. + +As mapping all permissions is infeasible both to calculate and store Cartography will only map in the relationships defined in the [permission relationship file](https://github.com/lyft/cartography/blob/master/cartography/data/permission_relationships.yaml) which includes some default permission mappings including s3 read access. + +You can specify your own permission mapping file using the `--permission-relationships-file` command line parameter + +#### Permission Mapping File +The [permission relationship file](https://github.com/lyft/cartography/blob/master/cartography/data/permission_relationships.yaml) is a yaml file that specifies what permission relationships should be created in the graph. It consists of RPR (Resource Permission Relationship) sections that are going to map specific permissions between AWSPrincipals and resources +```yaml +- target_label: S3Bucket + permissions: + - S3:GetObject + relationship_name: CAN_READ +``` +Each RPR consists of +- ResourceType (string) - The node Label that permissions will be built for +- Permissions (list(string)) - The list of permissions to map. If any of these permissions are present between a resource and a permission then the relationship is created. +- RelationshipName - (string) - The name of the relationship cartography will create + +It can also be used to absract many different permissions into one. This example combines all of the permissions that would allow a dynamodb table to be queried. +```yaml +- target_label: DynamoDBTable + permissions: + - dynamodb:BatchGetItem + - dynamodb:GetItem + - dynamodb:GetRecords + - dynamodb:Query + relationship_name: CAN_QUERY +``` +If a principal has any of the permission it will be mapped diff --git a/_sources/modules/aws/schema.md.txt b/_sources/modules/aws/schema.md.txt new file mode 100644 index 0000000000..81565b0291 --- /dev/null +++ b/_sources/modules/aws/schema.md.txt @@ -0,0 +1,3286 @@ +## AWS Schema + +.. _aws_schema: + +### AWSAccount + +Representation of an AWS Account. + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|name| The name of the account| +|inscope| Indicates that the account is part of the sync scope (true or false). +|foreign| Indicates if the account is not part of the sync scope (true or false). One such example is an account that is trusted as part of cross-account AWSRole trust not in scope for sync. +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The AWS Account ID number| + +#### Relationships +- Many node types belong to an `AWSAccount`. + + ``` + (AWSAccount)-[RESOURCE]->(AWSDNSZone, + AWSGroup, + AWSInspectorFinding, + AWSInspectorPackage, + AWSLambda, + AWSPrincipal, + AWSUser, + AWSVpc, + AutoScalingGroup, + DNSZone, + DynamoDBTable, + EBSSnapshot, + EBSVolume, + EC2Image, + EC2Instance, + EC2Reservation, + EC2ReservedInstance, + EC2SecurityGroup, + ElasticIPAddress, + ESDomain, + LaunchConfiguration, + LaunchTemplate, + LaunchTemplateVersion, + LoadBalancer, + RDSCluster, + RDSInstance, + RDSSnapshot, + SecretsManagerSecret, + SecurityHub, + SQSQueue + SSMInstanceInformation, + SSMInstancePatch) + ``` + +- An `AWSPolicy` node is defined for an `AWSAccount`. + + ``` + (AWSAccount)-[RESOURCE]->(AWSPolicy) + ``` + +- `AWSRole` nodes are defined in `AWSAccount` nodes. + + ``` + (AWSAccount)-[RESOURCE]->(AWSRole) + ``` + +### AWSCidrBlock +#### AWSIpv4CidrBlock +#### AWSIpv6CidrBlock +Representation of an [AWS CidrBlock used in VPC configuration](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_VpcCidrBlockAssociation.html). +The `AWSCidrBlock` defines the base label +type for `AWSIpv4CidrBlock` and `AWSIpv6CidrBlock` + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|cidr\_block| The CIDR block| +|block\_state| The state of the block| +|association\_id| the association id if the block is associated to a VPC +|lastupdated| Timestamp of the last time the node was updated| +|**id**| Unique identifier defined with the VPC association and the cidr\_block + +#### Relationships +- `AWSVpc` association + ``` + (AWSVpc)-[BLOCK_ASSOCIATION]->(AWSCidrBlock) + ``` +- Peering connection where `AWSCidrBlock` is an accepter or requester cidr. + ``` + (AWSCidrBlock)<-[REQUESTER_CIDR]-(AWSPeeringConnection) + (AWSCidrBlock)<-[ACCEPTER_CIDR]-(AWSPeeringConnection) + ``` + + Example of high level view of peering (without security group permissions) + ``` + MATCH p=(:AWSAccount)-[:RESOURCE|BLOCK_ASSOCIATION*..]->(:AWSCidrBlock)<-[:ACCEPTER_CIDR]-(:AWSPeeringConnection)-[:REQUESTER_CIDR]->(:AWSCidrBlock)<-[:RESOURCE|BLOCK_ASSOCIATION*..]-(:AWSAccount) + RETURN p + ``` + + Exploring detailed inbound peering rules + ``` + MATCH (outbound_account:AWSAccount)-[:RESOURCE|BLOCK_ASSOCIATION*..]->(:AWSCidrBlock)<-[:ACCEPTER_CIDR]-(:AWSPeeringConnection)-[:REQUESTER_CIDR]->(inbound_block:AWSCidrBlock)<-[:BLOCK_ASSOCIATION]-(inbound_vpc:AWSVpc)<-[:RESOURCE]-(inbound_account:AWSAccount) + WITH inbound_vpc, inbound_block, outbound_account, inbound_account + MATCH (inbound_range:IpRange{id: inbound_block.cidr_block})-[:MEMBER_OF_IP_RULE]->(inbound_rule:IpPermissionInbound)-[:MEMBER_OF_EC2_SECURITY_GROUP]->(inbound_group:EC2SecurityGroup)<-[:MEMBER_OF_EC2_SECURITY_GROUP]-(inbound_vpc) + RETURN outbound_account.name, inbound_account.name, inbound_range.range, inbound_rule.fromport, inbound_rule.toport, inbound_rule.protocol, inbound_group.name, inbound_vpc.id + ``` + +### AWSGroup + +Representation of AWS [IAM Groups](https://docs.aws.amazon.com/IAM/latest/APIReference/API_Group.html). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated| Timestamp of the last time the node was updated | +|path | The path to the group (IAM identifier, see linked docs above for details)| +| groupid| Unique string identifying the group | +|name | The friendly name that identifies the group| +| createdate| ISO 8601 date-time string when the group was created| +|**arn** | The AWS-global identifier for this group| + +#### Relationships +- Objects part of an AWSGroup may assume AWSRoles. + + ``` + (AWSGroup)-[STS_ASSUMEROLE_ALLOW]->(AWSRole) + ``` + +- AWSUsers and AWSPrincipals can be members of AWSGroups. + + ``` + (AWSUser, AWSPrincipal)-[MEMBER_AWS_GROUP]->(AWSGroup) + ``` + +- AWSGroups belong to AWSAccounts. + + ``` + (AWSAccount)-[RESOURCE]->(AWSGroup) + ``` + +### AWSInspectorFinding + +Representation of an AWS [Inspector Finding](https://docs.aws.amazon.com/inspector/v2/APIReference/API_Finding.html) + +| Field | Description | Required| +|-------|-------------|------|---| +|arn|The AWS ARN|yes +|id|Reuses the AWS ARN since it's unique|yes +|region|AWS region the finding is from|yes +|awsaccount|AWS account the finding is from|yes +|name|The finding name| +|instanceid|The instance ID of the EC2 instance with the issue| +|ecrimageid|The image ID of the ECR image with the issue| +|ecrrepositoryid|The repository ID of the ECR repository with the issue| +|severity|The finding severity| +|firstobservedat|Date the finding was first identified| +|updatedat|Date the finding was last updated| +|description|The finding description| +|type|The finding type| +|cvssscore|CVSS score of the finding| +|protocol|Network protocol for network findings| +|portrange|Port range affected for network findings| +|portrangebegin|Beginning of the port range affected for network findings| +|portrangeend|End of the port range affected for network findings| +|vulnerabilityid|Vulnerability ID associdated with the finding for package findings| +|referenceurls|Reference URLs for the found vulnerabilities| +|relatedvulnerabilities|A list of any related vulnerabilities| +|source|Source for the vulnerability| +|sourceurl|URL for the vulnerability source| +|vendorcreatedat|Date the vulnerability notice was created by the vendor| +|vendorseverity|Vendor chosen issue severity| +|vendorupdatedat|Date the vendor information was last updated| +|vulnerablepackageids|IDs for any related packages| + +#### Relationships + +- AWSInspectorFinding may affect EC2 Instances + + ``` + (AWSInspectorFinding)-[:AFFECTS]->(EC2Instance) + ``` + +- AWSInspectorFinding may affect ECR Repositories + + ``` + (AWSInspectorFinding)-[:AFFECTS]->(ECRRepository) + ``` + +- AWSInspectorFinding may affect ECR Images + + ``` + (AWSInspectorFinding)-[:AFFECTS]->(ECRImage) + ``` + +- AWSInspectorFindings belong to AWSAccounts. + + ``` + (AWSAccount)-[RESOURCE]->(AWSInspectorFinding) + ``` + +### AWSInspectorPackage + +Representation of an AWS [Inspector Finding Package](https://docs.aws.amazon.com/inspector/v2/APIReference/API_Finding.html) + +| Field | Description | Required| +|-------|-------------|------|---| +|**arn**|The AWS ARN|yes +|id|Uses the format of `name|arch|version|release|epoch` to uniqulely identify packages|yes +|region|AWS region the finding is from|yes +|awsaccount|AWS account the finding is from|yes +|findingarn|The AWS ARN for a related finding|yes +|name|The finding name| +|arch|Architecture for the package| +|version|Version of the package| +|release|Release of the package +|epoch|Package epoch| +|manager|Related package manager| +|filepath|Path to the file or package| +|fixedinversion|Version the related finding was fixed in| +|sourcelayerhash|Source layer hash for container images| + + +#### Relationships + +- AWSInspectorFindings have AWSInspectorPackages. + + ``` + (AWSInspectorFindings)-[HAS]->(AWSInspectorPackages) + ``` + +- AWSInspectorPackages belong to AWSAccounts. + + ``` + (AWSAccount)-[RESOURCE]->(AWSInspectorPackages) + ``` + +### AWSLambda + +Representation of an AWS [Lambda Function](https://docs.aws.amazon.com/lambda/latest/dg/API_FunctionConfiguration.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The arn of the lambda function| +| name | The name of the lambda function | +| modifieddate | Timestamp of the last time the function was last updated | +| runtime | The runtime environment for the Lambda function | +| description | The description of the Lambda function | +| timeout | The amount of time in seconds that Lambda allows a function to run before stopping it | +| memory | The memory that's allocated to the function | +| codesize | The size of the function's deployment package, in bytes. | +| handler | The function that Lambda calls to begin executing your function. | +| version | The version of the Lambda function. | +| tracingconfigmode | The function's AWS X-Ray tracing configuration mode. | +| revisionid | The latest updated revision of the function or alias. | +| state | The current state of the function. | +| statereason | The reason for the function's current state. | +| statereasoncode | The reason code for the function's current state. | +| lastupdatestatus | The status of the last update that was performed on the function. | +| lastupdatestatusreason | The reason for the last update that was performed on the function.| +| lastupdatestatusreasoncode | The reason code for the last update that was performed on the function. | +| packagetype | The type of deployment package. | +| signingprofileversionarn | The ARN of the signing profile version. | +| signingjobarn | The ARN of the signing job. | +| codesha256 | The SHA256 hash of the function's deployment package. | +| architectures | The instruction set architecture that the function supports. Architecture is a string array with one of the valid values. | +| masterarn | For Lambda@Edge functions, the ARN of the main function. | +| kmskeyarn | The KMS key that's used to encrypt the function's environment variables. This key is only returned if you've configured a customer managed key. | + +#### Relationships + +- AWSLambda function are resources in an AWS Account. + + ``` + (AWSAccount)-[RESOURCE]->(AWSLambda) + ``` + +- AWSLambda functions may act as AWSPrincipals via role assumption. + + ``` + (AWSLambda)-[STS_ASSUME_ROLE_ALLOW]->(AWSPrincipal) + ``` + +- AWSLambda functions may also have aliases. + + ``` + (AWSLambda)-[KNOWN_AS]->(AWSLambdaFunctionAlias) + ``` + +- AWSLambda functions may have the resource AWSLambdaEventSourceMapping. + + ``` + (AWSLambda)-[RESOURCE]->(AWSLambdaEventSourceMapping) + ``` + +- AWSLambda functions has AWS Lambda Layers. + + ``` + (AWSLambda)-[HAS]->(AWSLambdaLayer) + ``` + +- AWSLambda functions has AWS ECR Images. + + ``` + (AWSLambda)-[HAS]->(ECRImage) + ``` + +### AWSLambdaFunctionAlias + +Representation of an [AWSLambdaFunctionAlias](https://docs.aws.amazon.com/lambda/latest/dg/configuration-aliases.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The arn of the lambda function alias| +| name | The name of the lambda function alias | +| functionversion | The function version that the alias invokes.| +| revisionid | A unique identifier that changes when you update the alias. | +| description | The description of the alias. | + +#### Relationships + +- AWSLambda functions may also have aliases. + + ``` + (AWSLambda)-[KNOWN_AS]->(AWSLambdaFunctionAlias) + ``` + +### AWSLambdaEventSourceMapping + +Representation of an [AWSLambdaEventSourceMapping](https://docs.aws.amazon.com/lambda/latest/dg/API_ListEventSourceMappings.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The id of the event source mapping| +| batchsize | The maximum number of items to retrieve in a single batch. | +| startingposition | The position in a stream from which to start reading. | +| startingpositiontimestamp | The time from which to start reading. | +| parallelizationfactor | The number of batches to process from each shard concurrently. | +| maximumbatchingwindowinseconds | The maximum amount of time to gather records before invoking the function, in seconds.| +| eventsourcearn |The Amazon Resource Name (ARN) of the event source.| +| lastmodified |The date that the event source mapping was last updated, or its state changed.| +| state | The state of the event source mapping. | +| maximumrecordage | Discard records older than the specified age. | +| bisectbatchonfunctionerror | If the function returns an error, split the batch in two and retry. | +| maximumretryattempts | Discard records after the specified number of retries. | +| tumblingwindowinseconds | The duration in seconds of a processing window. | +| lastprocessingresult |The result of the last AWS Lambda invocation of your Lambda function. | + +#### Relationships + +- AWSLambda functions may have the resource AWSLambdaEventSourceMapping. + + ``` + (AWSLambda)-[RESOURCE]->(AWSLambdaEventSourceMapping) + ``` + +### AWSLambdaLayer + +Representation of an [AWSLambdaLayer](https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The arn of the lambda function layer| +| codesize | The size of the layer archive in bytes.| +| signingprofileversionarn | The Amazon Resource Name (ARN) for a signing profile version.| +| signingjobarn | The Amazon Resource Name (ARN) of a signing job. | + +#### Relationships + +- AWSLambda functions has AWS Lambda Layers. + + ``` + (AWSLambda)-[HAS]->(AWSLambdaLayer) + ``` + +### AWSPolicy + +Representation of an [AWS Policy](https://docs.aws.amazon.com/IAM/latest/APIReference/API_Policy.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| name | The friendly name (not ARN) identifying the policy | +| createdate | ISO 8601 date-time when the policy was created| +| type | "inline" or "managed" - the type of policy it is| +| arn | The arn for this object | +| **id** | The unique identifer for a policy. If the policy is managed this will be the Arn. If the policy is inline this will calculated as _AWSPrincipal_/inline_policy/_PolicyName_| + + +#### Relationships + +- `AWSPrincipal` contains `AWSPolicy` + + ``` + (AWSPrincipal)-[POLICY]->(AWSPolicy) + ``` + +- `AWSPolicy` contains `AWSPolicyStatement` + + ``` + (AWSPolicy)-[STATEMENTS]->(AWSPolicyStatement) + ``` + +### AWSPolicyStatement + +Representation of an [AWS Policy Statement](https://docs.aws.amazon.com/IAM/latest/APIReference/API_Statement.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| resources | (array) The resources the statement is applied to. Can contain wildcards | +| actions | (array) The permissions allowed or denied by the statement. Can contain wildcards | +| notactions | (array) The permission explicitly not matched by the statement | +| effect | "Allow" or "Deny" - the effect of this statement | +| **id** | The unique identifier for a statement.
If the statement has an Sid the id will be calculated as _AWSPolicy.id_/statements/_Sid_.
If the statement has no Sid the id will be calculated as _AWSPolicy.id_/statements/_index of statement in statement list_ | + + +#### Relationships + +- `AWSPolicy` contains `AWSPolicyStatement` + + ``` + (AWSPolicy)-[STATEMENTS]->(AWSPolicyStatement) + ``` + + +### AWSPrincipal +Representation of an [AWSPrincipal](https://docs.aws.amazon.com/IAM/latest/APIReference/API_User.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| path | The path to the principal | +| name | The friendly name of the principal | +| createdate | ISO 8601 date-time when the principal was created | +| **arn** | AWS-unique identifier for this object | +| userid | The stable and unique string identifying the principal. | +| passwordlastused | Datetime when this principal's password was last used + + +#### Relationships + +- AWS Principals can be members of AWS Groups. + + ``` + (AWSPrincipal)-[MEMBER_AWS_GROUP]->(AWSGroup) + ``` + +- This AccountAccessKey is used to authenticate to this AWSPrincipal. + + ``` + (AWSPrincipal)-[AWS_ACCESS_KEY]->(AccountAccessKey) + ``` + +- AWS Roles can trust AWS Principals. + + ``` + (AWSRole)-[TRUSTS_AWS_PRINCIPAL]->(AWSPrincipal) + ``` + +- AWS Accounts contain AWS Principals. + + ``` + (AWSAccount)-[RESOURCE]->(AWSPrincipal) + ``` + +- Redshift clusters may assume IAM roles. See [this article](https://docs.aws.amazon.com/redshift/latest/mgmt/authorizing-redshift-service.html). + + ``` + (RedshiftCluster)-[STS_ASSUMEROLE_ALLOW]->(AWSPrincipal) + ``` + +### AWSPrincipal::AWSUser +Representation of an [AWSUser](https://docs.aws.amazon.com/IAM/latest/APIReference/API_User.html). An AWS User is a type of AWS Principal. + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| path | The path to the user | +| name | The friendly name of the user | +| createdate | ISO 8601 date-time when the user was created | +| **arn** | AWS-unique identifier for this object | +| userid | The stable and unique string identifying the user. | +| passwordlastused | Datetime when this user's password was last used + +#### Relationships +- AWS Users can be members of AWS Groups. + + ``` + (AWSUser)-[MEMBER_AWS_GROUP]->(AWSGroup) + ``` + +- AWS Users can assume AWS Roles. + + ``` + (AWSUser)-[STS_ASSUMEROLE_ALLOW]->(AWSRole) + ``` + +- This AccountAccessKey is used to authenticate to this AWSUser + + ``` + (AWSUser)-[AWS_ACCESS_KEY]->(AccountAccessKey) + ``` + +- AWS Accounts contain AWS Users. + + ``` + (AWSAccount)-[RESOURCE]->(AWSUser) + ``` + + +### AWSPrincipal::AWSRole + +Representation of an AWS [IAM Role](https://docs.aws.amazon.com/IAM/latest/APIReference/API_Role.html). An AWS Role is a type of AWS Principal. + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| roleid | The stable and unique string identifying the role. | +| name | The friendly name that identifies the role.| +| createdate| The date and time, in ISO 8601 date-time format, when the role was created. | +| **arn** | AWS-unique identifier for this object | + + +#### Relationships + +- Some AWS Groups, Users, Principals, and EC2 Instances can assume AWS Roles. + + ``` + (AWSGroup, AWSUser, EC2Instance)-[STS_ASSUMEROLE_ALLOW]->(AWSRole) + ``` + +- Some AWS Roles can assume other AWS Roles. + + ``` + (AWSRole)-[STS_ASSUMEROLE_ALLOW]->(AWSRole) + ``` + +- Some AWS Roles trust AWS Principals. + + ``` + (AWSRole)-[TRUSTS_AWS_PRINCIPAL]->(AWSPrincipal) + ``` + +- AWS Roles are defined in AWS Accounts. + + ``` + (AWSAccount)-[RESOURCE]->(AWSRole) + ``` + +### AWSTransitGateway +Representation of an [AWS Transit Gateway](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_TransitGateway.html). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|owner\_id| The ID of the AWS account that owns the transit gateway| +|description| Transit Gateway description| +|state| Can be one of ``pending \| available \| modifying \| deleting \| deleted``| +|tgw_id| Unique identifier of the Transit Gateway| +|**id**| Unique identifier of the Transit Gateway| +| **arn** | AWS-unique identifier for this object (same as `id`) | + +#### Relationships +- Transit Gateways belong to one `AWSAccount`... +``` +(AWSAccount)-[RESOURCE]->(AWSTransitGateway) +``` + +- ... and can be shared with other accounts +``` +(AWSAccount)<-[SHARED_WITH]-(AWSTransitGateway) +``` + +- `AWSTag` +``` +(AWSTransitGateway)-[TAGGED]->(AWSTag) +``` + +### AWSTransitGatewayAttachment +Representation of an [AWS Transit Gateway Attachment](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_TransitGatewayAttachment.html). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|resource\_type| Can be one of ``vpc \| vpn \| direct-connect-gateway \| tgw-peering`` | +|state| Can be one of ``initiating \| pendingAcceptance \| rollingBack \| pending \| available \| modifying \| deleting \| deleted \| failed \| rejected \| rejecting \| failing`` +|**id**| Unique identifier of the Transit Gateway Attachment | + +#### Relationships +- `AWSAccount` +``` +(AWSAccount)-[RESOURCE]->(AWSTransitGatewayAttachment) +``` +- `AWSVpc` (for VPC attachments) +``` +(AWSVpc)-[RESOURCE]->(AWSTransitGatewayAttachment {resource_type: 'vpc'}) +``` +- `AWSTransitGateway` attachment +``` +(AWSTransitGateway)<-[ATTACHED_TO]-(AWSTransitGatewayAttachment) +``` +- `AWSTag` +``` +(AWSTransitGatewayAttachment)-[TAGGED]->(AWSTag) +``` + +### AWSVpc +Representation of an [AWS CidrBlock used in VPC configuration](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_VpcCidrBlockAssociation.html). +More information on https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-vpcs.html + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|vpcid| The VPC unique identifier| +|primary\_cidr\_block|The primary IPv4 CIDR block for the VPC.| +|instance\_tenancy| The allowed tenancy of instances launched into the VPC.| +|state| The current state of the VPC.| +|region| (optional) the region of this VPC. This field is only available on VPCs in your account. It is not available on VPCs that are external to your account and linked via a VPC peering relationship. +|**id**| Unique identifier defined VPC node (vpcid) + +#### Relationships +- `AWSAccount` resource + ``` + (AWSAccount)-[RESOURCE]->(AWSVpc) + ``` +- `AWSVpc` and `AWSCidrBlock` association + ``` + (AWSVpc)-[BLOCK_ASSOCIATION]->(AWSCidrBlock) + ``` +- `AWSVpc` and `EC2SecurityGroup` membership association + ``` + (AWSVpc)<-[MEMBER_OF_EC2_SECURITY_GROUP]-(EC2SecurityGroup) + ``` +- AWS VPCs can be tagged with AWSTags. + ``` + (AWSVpc)-[TAGGED]->(AWSTag) + ``` +- Redshift clusters can be members of AWSVpcs. + ``` + (RedshiftCluster)-[MEMBER_OF_AWS_VPC]->(AWSVpc) + ``` +- Peering connection where `AWSVpc` is an accepter or requester vpc. + ``` + (AWSVpc)<-[REQUESTER_VPC]-(AWSPeeringConnection) + (AWSVpc)<-[ACCEPTER_VPC]-(AWSPeeringConnection) + ``` + + +### Tag::AWSTag + +Representation of an AWS [Tag](https://docs.aws.amazon.com/resourcegroupstagging/latest/APIReference/API_Tag.html). AWS Tags can be applied to many objects. + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | This tag's unique identifier of the format `{TagKey}:{TagValue}`. We fabricated this ID. | +| key | One part of a key-value pair that makes up a tag.| +| value | One part of a key-value pair that makes up a tag. | +| region | The region where this tag was discovered.| + +#### Relationships +- AWS VPCs, DB Subnet Groups, EC2 Instances, EC2 SecurityGroups, EC2 Subnets, EC2 Network Interfaces, RDS Instances, and S3 Buckets can be tagged with AWSTags. + ``` + (AWSVpc, DBSubnetGroup, EC2Instance, EC2SecurityGroup, EC2Subnet, NetworkInterface, RDSInstance, S3Bucket)-[TAGGED]->(AWSTag) + ``` + +### AccountAccessKey + +Representation of an AWS [Access Key](https://docs.aws.amazon.com/IAM/latest/APIReference/API_AccessKey.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated +| createdate | Date when access key was created | +| status | Active: valid for API calls. Inactive: not valid for API calls| +| lastuseddate | Date when the key was last used | +| lastusedservice | The service that was last used with the access key | +| lastusedregion | The region where the access key was last used | +| **accesskeyid** | The ID for this access key| + +#### Relationships +- Account Access Keys may authenticate AWS Users and AWS Principal objects. + + ``` + (AWSUser, AWSPrincipal)-[AWS_ACCESS_KEY]->(AccountAccessKey) + ``` + + +### DBSubnetGroup + +Representation of an RDS [DB Subnet Group](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DBSubnetGroup.html). For more information on how RDS instances interact with these, please see [this article](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_VPC.WorkingWithRDSInstanceinaVPC.html). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job first discovered this node | +|id| The ARN of the DBSubnetGroup| +|name | The name of DBSubnetGroup | +|lastupdated| Timestamp of the last time the node was updated| +|description| Description of the DB Subnet Group| +|status| The status of the group | +|vpc\_id| The ID of the VPC (Virtual Private Cloud) that this DB Subnet Group is associated with.| +|value| The IP address that the DNSRecord points to| + +#### Relationships + +- RDS Instances are part of DB Subnet Groups + ``` + (RDSInstance)-[:MEMBER_OF_DB_SUBNET_GROUP]->(DBSubnetGroup) + ``` + +- DB Subnet Groups consist of EC2 Subnets + ``` + (DBSubnetGroup)-[:RESOURCE]->(EC2Subnet) + ``` + +- DB Subnet Groups can be tagged with AWSTags. + + ``` + (DBSubnetGroup)-[TAGGED]->(AWSTag) + ``` + + +### DNSRecord + +Representation of a generic DNSRecord. + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job first discovered this node | +|name| The name of the DNSRecord| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The name of the DNSRecord concatenated with the record type| +|type| The record type of the DNS record| +|value| The IP address that the DNSRecord points to| + +#### Relationships + +- DNSRecords can point to IP addresses. + + ``` + (DNSRecord)-[DNS_POINTS_TO]->(Ip) + ``` + + +- DNSRecords/AWSDNSRecords can point to each other. + + ``` + (AWSDNSRecord, DNSRecord)-[DNS_POINTS_TO]->(AWSDNSRecord, DNSRecord) + ``` + + +- DNSRecords can point to LoadBalancers. + + ``` + (DNSRecord)-[DNS_POINTS_TO]->(LoadBalancer) + ``` + + +- DNSRecords can be members of DNSZones. + + ``` + (DNSRecord)-[MEMBER_OF_DNS_ZONE]->(DNSZone) + ``` + + +### DNSRecord::AWSDNSRecord + +Representation of an AWS DNS [ResourceRecordSet](https://docs.aws.amazon.com/Route53/latest/APIReference/API_ResourceRecordSet.html). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job first discovered this node | +|name| The name of the DNSRecord| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The zoneid for the record, the value of the record, and the type concatenated together| +|type| The record type of the DNS record| +|value| If it is an A, ALIAS, or CNAME record, this is the IP address that the DNSRecord points to. If it is an NS record, the `name` is used here.| + +#### Relationships +- DNSRecords/AWSDNSRecords can point to each other. + + ``` + (AWSDNSRecord, DNSRecord)-[DNS_POINTS_TO]->(AWSDNSRecord, DNSRecord) + ``` + + +- AWSDNSRecords can point to LoadBalancers. + + ``` + (AWSDNSRecord)-[DNS_POINTS_TO]->(LoadBalancer, ESDomain) + ``` + + +- AWSDNSRecords can be members of AWSDNSZones. + + ``` + (AWSDNSRecord)-[MEMBER_OF_DNS_ZONE]->(AWSDNSZone) + ``` + + +### DNSZone +Representation of a generic DNS Zone. + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated| Timestamp of the last time the node was updated | +|**name**| the name of the DNS zone| +| comment | Comments about the zone | + + +#### Relationships + +- DNSRecords can be members of DNSZones. + + ``` + (DNSRecord)-[MEMBER_OF_DNS_ZONE]->(DNSZone) + ``` + + +### DNSZone::AWSDNSZone + +Representation of an AWS DNS [HostedZone](https://docs.aws.amazon.com/Route53/latest/APIReference/API_HostedZone.html). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job first discovered this node | +|**name**| the name of the DNS zone| +| zoneid| The zoneid defined by Amazon Route53| +| lastupdated| Timestamp of the last time the node was updated | +| comment| Comments about the zone | +| privatezone | Whether or not this is a private DNS zone | + +#### Relationships + +- AWSDNSZones and DNSZones can be part of AWSAccounts. + + ``` + (AWSAccount)-[RESOURCE]->(AWSDNSZone) + ``` + +- AWSDNSRecords can be members of AWSDNSZones. + + ``` + (AWSDNSRecord)-[MEMBER_OF_DNS_ZONE]->(AWSDNSZone) + ``` +- AWSDNSZone can have subzones hosted by another AWSDNSZone + ``` + (AWSDNSZone)<-[SUBZONE]-(AWSDNSZone) + ``` + + +### DynamoDBTable + +Representation of an AWS [DynamoDBTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ListTables.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| name | The name of the table | +| **id** | The ARN of the table | +| region | The AWS region of the table | +| **arn** | The AWS-unique identifier + +#### Relationships +- DynamoDBTables belong to AWS Accounts. + + ``` + (AWSAccount)-[RESOURCE]->(DynamoDBTable) + ``` + + +### EC2Instance + +Our representation of an AWS [EC2 Instance](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_Instance.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | Same as `instanceid` below. | +| instanceid | The instance id provided by AWS. This is [globally unique](https://forums.aws.amazon.com/thread.jspa?threadID=137203) | +| publicdnsname | The public DNS name assigned to the instance | +| publicipaddress | The public IPv4 address assigned to the instance if applicable | +| privateipaddress | The private IPv4 address assigned to the instance | +| imageid | The ID of the [Amazon Machine Image](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html) used to launch the instance | +| subnetid | The ID of the EC2Subnet associated with this instance | +| instancetype | The instance type. See API docs linked above for specifics. | +| iaminstanceprofile | The IAM instance profile associated with the instance, if applicable. | +| launchtime | The time the instance was launched | +| monitoringstate | Whether monitoring is enabled. Valid Values: disabled, disabling, enabled, pending. | +| state | The [current state](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_InstanceState.html) of the instance. +| launchtimeunix | The time the instance was launched in unix time | +| region | The AWS region this Instance is running in| +| exposed\_internet | The `exposed_internet` flag on an EC2 instance is set to `True` when (1) the instance is part of an EC2 security group or is connected to a network interface connected to an EC2 security group that allows connectivity from the 0.0.0.0/0 subnet or (2) the instance is connected to an Elastic Load Balancer that has its own `exposed_internet` flag set to `True`. | +| availabilityzone | The Availability Zone of the instance.| +| tenancy | The tenancy of the instance.| +| hostresourcegrouparn | The ARN of the host resource group in which to launch the instances.| +| platform | The value is `Windows` for Windows instances; otherwise blank.| +| architecture | The architecture of the image.| +| ebsoptimized | Indicates whether the instance is optimized for Amazon EBS I/O. | +| bootmode | The boot mode of the instance.| +| instancelifecycle | Indicates whether this is a Spot Instance or a Scheduled Instance.| +| hibernationoptions | Indicates whether the instance is enabled for hibernation.| + + +#### Relationships + +- EC2 Instances can be part of subnets + + ``` + (EC2Instance)-[PART_OF_SUBNET]->(EC2Subnet) + ``` + +- EC2 Instances can have NetworkInterfaces connected to them + + ``` + (EC2Instance)-[NETWORK_INTERFACE]->(NetworkInterface) + ``` + +- EC2 Instances may be members of EC2 Reservations + + ``` + (EC2Instance)-[MEMBER_OF_EC2_RESERVATION]->(EC2Reservation) + ``` + +- EC2 Instances can be part of EC2 Security Groups + + ``` + (EC2Instance)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup) + ``` + +- Load Balancers can expose (be connected to) EC2 Instances + + ``` + (LoadBalancer)-[EXPOSE]->(EC2Instance) + ``` + +- Package and Dependency nodes can be deployed in EC2 Instances. + + ``` + (Package, Dependency)-[DEPLOYED]->(EC2Instance) + ``` + +- AWS Accounts contain EC2 Instances. + + ``` + (AWSAccount)-[RESOURCE]->(EC2Instance) + ``` + +- EC2 Instances can be tagged with AWSTags. + + ``` + (EC2Instance)-[TAGGED]->(AWSTag) + ``` + +- AWS EBS Volumes are attached to an EC2 Instance + + ``` + (EBSVolume)-[ATTACHED_TO]->(EC2Instance) + ``` + +- EC2 Instances can assume IAM Roles. + + ``` + (EC2Instance)-[STS_ASSUMEROLE_ALLOW]->(AWSRole) + ``` + +- EC2Instances can have SSMInstanceInformation + + ``` + (EC2Instance)-[HAS_INFORMATION]->(SSMInstanceInformation) + ``` + +- EC2Instances can have SSMInstancePatches + + ``` + (EC2Instance)-[HAS_PATCH]->(SSMInstancePatch) + ``` + +### EC2KeyPair + +Representation of an AWS [EC2 Key Pair](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_KeyPairInfo.html) + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| keyname | The name of the key pair | +| keyfingerprint | The fingerprint of the public key | +| region| The AWS region | +| **arn** | AWS-unique identifier for this object | +| id | same as `arn` | +| user_uploaded | `user_uploaded` is set to `True` if the the KeyPair was uploaded to AWS. Uploaded KeyPairs will have 128-bit MD5 hashed `keyfingerprint`, and KeyPairs from AWS will have 160-bit SHA-1 hashed `keyfingerprint`s. | +| duplicate_keyfingerprint | `duplicate_keyfingerprint` is set to `True` if the KeyPair has the same `keyfingerprint` as another KeyPair. | + +#### Relationships + +- EC2 key pairs are contained in AWS Accounts. + + ``` + (AWSAccount)-[RESOURCE]->(EC2KeyPair) + ``` + +- EC2 key pairs can be used to log in to AWS EC2 isntances. + + ``` + (EC2KeyPair)-[SSH_LOGIN_TO]->(EC2Instance) + ``` + +- EC2 key pairs have matching `keyfingerprint`. + + ``` + (EC2KeyPair)-[MATCHING_FINGERPRINT]->(EC2KeyPair) + ``` + +### EC2PrivateIp +Representation of an AWS EC2 [InstancePrivateIpAddress](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_InstancePrivateIpAddress.html) + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| network_interface_id | id of the network interface with which the IP is associated with | +| primary | Indicates whether this IPv4 address is the primary private IP address of the network interface. | +| private_ip_address | The private IPv4 address of the network interface. | +| public_ip | The public IP address or Elastic IP address bound to the network interface. | +| ip_owner_id | Id of the owner, e.g. `amazon-elb` for ELBs | + +#### Relationships + +- EC2PrivateIps are connected with NetworkInterfaces. + + ``` + (NetworkInterface)-[PRIVATE_IP_ADDRESS]->(EC2PrivateIp) + ``` + + +### EC2Reservation +Representation of an AWS EC2 [Reservation](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_Reservation.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| requesterid | The ID of the requester that launched the instances on your behalf | +| **reservationid** | The ID of the reservation. | +| region| The AWS region | +| ownerid | The ID of the AWS account that owns the reservation. | + +#### Relationships + +- EC2 reservations are contained in AWS Accounts. + + ``` + (AWSAccount)-[RESOURCE]->(EC2Reservation) + ``` + +- EC2 Instances are members of EC2 reservations. + + ``` + (EC2Instance)-[MEMBER_OF_EC2_RESERVATION]->(EC2Reservation) + ``` + + +### EC2SecurityGroup +Representation of an AWS EC2 [Security Group](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_SecurityGroup.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| groupid | The ID of the security group| +| name | The name of the security group| +| description | A description of the security group| +| **id** | Same as `groupid` | +| region | The AWS region this security group is installed in| + + +#### Relationships + +- EC2 Instances, Network Interfaces, Load Balancers, Elastic Search Domains, IP Rules, IP Permission Inbound nodes, and RDS Instances can be members of EC2 Security Groups. + + ``` + (EC2Instance, + NetworkInterface, + LoadBalancer, + ESDomain, + IpRule, + IpPermissionInbound, + RDSInstance, + AWSVpc)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup) + ``` + +- Load balancers can define inbound [Source Security Groups](https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-security-groups.html). + + ``` + (LoadBalancer)-[SOURCE_SECURITY_GROUP]->(EC2SecurityGroup) + ``` + +- AWS Accounts contain EC2 Security Groups. + + ``` + (AWSAccount)-[RESOURCE]->(EC2SecurityGroup) + ``` + +- EC2 SecurityGroups can be tagged with AWSTags. + + ``` + (EC2SecurityGroup)-[TAGGED]->(AWSTag) + ``` + +- Redshift clusters can be members of EC2 Security Groups. + + ``` + (RedshiftCluster)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup) + ``` + + +### EC2Subnet + +Representation of an AWS EC2 [Subnet](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_Subnet.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **subnetid** | The ID of the subnet| +| **id** | same as subnetid | +| region| The AWS region the subnet is installed on| +| name | The IPv4 CIDR block assigned to the subnet| +| cidr_block | The IPv4 CIDR block assigned to the subnet| +| available_ip_address_count | The number of unused private IPv4 addresses in the subnet. The IPv4 addresses for any stopped instances are considered unavailable | +| default_for_az | Indicates whether this is the default subnet for the Availability Zone. | +| map_customer_owned_ip_on_launch | Indicates whether a network interface created in this subnet (including a network interface created by RunInstances ) receives a customer-owned IPv4 address | +| map_public_ip_on_launch | Indicates whether instances launched in this subnet receive a public IPv4 address | +| subnet_arn | The Amazon Resource Name (ARN) of the subnet | +| availability_zone | The Availability Zone of the subnet | +| availability_zone_id | The AZ ID of the subnet | +| state | The current state of the subnet. | +| assignipv6addressoncreation | Indicates whether a network interface created in this subnet (including a network interface created by RunInstances ) receives an IPv6 address. | + + +#### Relationships + +- A Network Interface can be part of an EC2 Subnet. + + ``` + (NetworkInterface)-[PART_OF_SUBNET]->(EC2Subnet) + ``` + +- An EC2 Instance can be part of an EC2 Subnet. + + ``` + (EC2Instance)-[PART_OF_SUBNET]->(EC2Subnet) + ``` + +- A LoadBalancer can be part of an EC2 Subnet. + + ``` + (LoadBalancer)-[SUBNET]->(EC2Subnet) + + ``` + +- A LoadBalancer can be part of an EC2 Subnet. + + ``` + (LoadBalancer)-[PART_OF_SUBNET]->(EC2Subnet) + ``` + +- A LoadBalancerV2 can be part of an EC2 Subnet. + + ``` + (LoadBalancerV2)-[PART_OF_SUBNET]->(EC2Subnet) + ``` + + +- DB Subnet Groups consist of EC2 Subnets + ``` + (DBSubnetGroup)-[RESOURCE]->(EC2Subnet) + ``` + + +- EC2 Subnets can be tagged with AWSTags. + + ``` + (EC2Subnet)-[TAGGED]->(AWSTag) + ``` + +- EC2 Subnets are member of a VPC. + + ``` + (EC2Subnet)-[MEMBER_OF_AWS_VPC]->(AWSVpc) + ``` + +- EC2 Subnets belong to AWS Accounts + + ``` + (AWSAccount)-[RESOURCE]->(EC2Subnet) + ``` + +- EC2PrivateIps are connected with NetworkInterfaces. + + (NetworkInterface)-[PRIVATE_IP_ADDRESS]->(EC2PrivateIp) + + +### AWSInternetGateway + + Representation of an AWS [Interent Gateway](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_InternetGateway.html). + + | Field | Description | + |--------|-----------| + | **id** | Internet gateway ID | + | arn | Amazon Resource Name | + | region | The region of the gateway | + + +#### Relationships + + - Internet Gateways are attached to a VPC. + + ``` + (AWSInternetGateway)-[ATTACHED_TO]->(AWSVpc) + ``` + + - Internet Gateways belong to AWS Accounts + + ``` + (AWSAccount)-[RESOURCE]->(AWSInternetGateway) + ``` + +### ECRRepository + +Representation of an AWS Elastic Container Registry [Repository](https://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_Repository.html). + +| Field | Description | +|--------|-----------| +| **id** | Same as ARN | +| arn | The ARN of the repository | +| name | The name of the repository | +| region | The region of the repository | +| created_at | Date and time when the repository was created | + +#### Relationships + +- An ECRRepository contains ECRRepositoryImages: + ``` + (:ECRRepository)-[:REPO_IMAGE]->(:ECRRepositoryImage) + ``` + + +### ECRRepositoryImage + +An ECR image may be referenced and tagged by more than one ECR Repository. To best represent this, we've created an +`ECRRepositoryImage` node as a layer of indirection between the repo and the image. + +More concretely explained, we run +[`ecr.list_images()`](https://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_ImageIdentifier.html), and then +store the image tag on an `ECRRepositoryImage` node and the image digest hash on a separate `ECRImage` node. + +This way, more than one `ECRRepositoryImage` can reference/be connected to the same `ECRImage`. + +| Field | Description | +|--------|-----------| +| tag | The tag applied to the repository image, e.g. "latest" | +| uri | The URI where the repository image is stored | +| **id** | same as uri | + +#### Relationships + +- An ECRRepository contains ECRRepositoryImages: + ``` + (:ECRRepository)-[:REPO_IMAGE]->(:ECRRepositoryImage) + ``` + +- ECRRepositoryImages reference ECRImages + ``` + (:ECRRepositoryImage)-[:IMAGE]->(:ECRImage) + ``` + + +### ECRImage + +Representation of an ECR image identified by its digest (e.g. a SHA hash). Specifically, this is the "digest part" of +[`ecr.list_images()`](https://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_ImageIdentifier.html). Also see +ECRRepositoryImage. + +| Field | Description | +|--------|-----------| +| digest | The hash of this ECR image | +| **id** | Same as digest | + +#### Relationships + +- ECRRepositoryImages reference ECRImages + ``` + (:ECRRepositoryImage)-[:IMAGE]->(:ECRImage) + ``` + +- Software packages are a part of ECR Images + ``` + (:Package)-[:DEPLOYED]->(:ECRImage) + ``` + + +### Package + +Representation of a software package, as found by an AWS ECR vulnerability scan. + +| Field | Description | +|-------|-------------| +| **id** | Concatenation of ``{version}\|{name}`` | +| version | The version of the package, includes the Linux distro that it was built for | +| name | The name of the package | + +#### Relationships + +- Software packages are a part of ECR Images + ``` + (:Package)-[:DEPLOYED]->(:ECRImage) + ``` + +- AWS ECR scans yield ECRScanFindings that affect software packages + ``` + (:ECRScanFindings)-[:AFFECTS]->(:Package) + ``` + + +### ECRScanFinding (:Risk:CVE) + +Representation of a scan finding from AWS ECR. This is the result output of [`ecr.describe_image_scan_findings()`](https://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_DescribeImageScanFindings.html). + +| Field | Description | +|--------|-----------| +| name | The name of the ECR scan finding, e.g. a CVE name | +| **id** | Same as name | +| severity | The severity of the risk | +| uri | A URI link to a descriptive article on the risk | + +#### Relationships + +- AWS ECR scans yield ECRScanFindings that affect software packages + ``` + (:ECRScanFindings)-[:AFFECTS]->(:Package) + ``` + + + +### EKSCluster + +Representation of an AWS [EKS Cluster](https://docs.aws.amazon.com/eks/latest/APIReference/API_Cluster.html). + +| Field | Description | +|-------|-------------| +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| created_at | The date and time the cluster was created | +| region | The AWS region | +| **arn** | AWS-unique identifier for this object | +| id | same as `arn` | +| name | Name of the EKS Cluster | +| endpoint | The endpoint for the Kubernetes API server. | +| endpoint_public_access | Indicates whether the Amazon EKS public API server endpoint is enabled | +| exposed_internet | Set to True if the EKS Cluster public API server endpoint is enabled | +| rolearn | The ARN of the IAM role that provides permissions for the Kubernetes control plane to make calls to AWS API | +| version | Kubernetes version running | +| platform_version | Version of EKS | +| status | Status of the cluster. Valid Values: creating, active, deleting, failed, updating | +| audit_logging | Whether audit logging is enabled | + +#### Relationships + +- EKS Clusters belong to AWS Accounts. + ``` + (AWSAccount)-[RESOURCE]->(EKSCluster) + ``` + +### EMRCluster + +Representation of an AWS [EMR Cluster](https://docs.aws.amazon.com/emr/latest/APIReference/API_Cluster.html). + +| Field | Description | +|-------|-------------| +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| region | The AWS region | +| **arn** | AWS-unique identifier for this object | +| id | The Id of the EMR Cluster. | +| instance\_collection\_type | The instance group configuration of the cluster. A value of INSTANCE\_GROUP indicates a uniform instance group configuration. A value of INSTANCE\_FLEET indicates an instance fleets configuration. | +| log\_encryption\_kms\_key\_id | The KMS key used for encrypting log files. | +| requested\_ami\_version | The AMI version requested for this cluster. | +| running\_ami\_version | The AMI version running on this cluster. | +| release\_label | The Amazon EMR release label, which determines the version of open-source application packages installed on the cluster. | +| auto\_terminate | Specifies whether the cluster should terminate after completing all steps. | +| termination\_protected | Indicates whether Amazon EMR will lock the cluster to prevent the EC2 instances from being terminated by an API call or user intervention, or in the event of a cluster error. | +| visible\_to\_all\_users | Indicates whether the cluster is visible to IAM principals in the Amazon Web Services account associated with the cluster. | +| master\_public\_dns\_name | The DNS name of the master node. If the cluster is on a private subnet, this is the private DNS name. On a public subnet, this is the public DNS name. | +| security\_configuration | The name of the security configuration applied to the cluster. | +| autoscaling\_role | An IAM role for automatic scaling policies. | +| scale\_down\_behavior | The way that individual Amazon EC2 instances terminate when an automatic scale-in activity occurs or an instance group is resized. | +| custom\_ami\_id | The ID of a custom Amazon EBS-backed Linux AMI if the cluster uses a custom AMI. | +| repo\_upgrade\_on\_boot | Specifies the type of updates that are applied from the Amazon Linux AMI package repositories when an instance boots using the AMI. | +| outpost\_arn | The Amazon Resource Name (ARN) of the Outpost where the cluster is launched. | +| log\_uri | The path to the Amazon S3 location where logs for this cluster are stored. | +| servicerole | Service Role of the EMR Cluster | + + +#### Relationships + +- EMR Clusters belong to AWS Accounts. + ``` + (AWSAccount)-[RESOURCE]->(EMRCluster) + ``` + + +### ESDomain + +Representation of an AWS [ElasticSearch Domain](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-configuration-api.html#es-configuration-api-datatypes) (see ElasticsearchDomainConfig). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| elasticsearch\_cluster\_config\_instancetype | The instancetype | +| elasticsearch\_version | The version of elasticsearch | +| elasticsearch\_cluster\_config\_zoneawarenessenabled | Indicates whether multiple Availability Zones are enabled. | +| elasticsearch\_cluster\_config\_dedicatedmasterenabled | Indicates whether dedicated master nodes are enabled for the cluster. True if the cluster will use a dedicated master node. False if the cluster will not. | +| elasticsearch\_cluster\_config\_dedicatedmastercount |Number of dedicated master nodes in the cluster.| +| elasticsearch\_cluster\_config\_dedicatedmastertype | Amazon ES instance type of the dedicated master nodes in the cluster.| +| domainid | Unique identifier for an Amazon ES domain. | +| encryption\_at\_rest\_options\_enabled | Specify true to enable encryption at rest. | +| deleted | Status of the deletion of an Amazon ES domain. True if deletion of the domain is complete. False if domain deletion is still in progress. | +| **id** | same as `domainid` | +| **arn** |Amazon Resource Name (ARN) of an Amazon ES domain. | +| exposed\_internet | `exposed_internet` is set to `True` if the ElasticSearch domain has a policy applied to it that makes it internet-accessible. This policy determination is made by using the [policyuniverse](https://github.com/Netflix-Skunkworks/policyuniverse) library. The code for this augmentation is implemented at `cartography.intel.aws.elasticsearch._process_access_policy()`. | + +#### Relationships + +- Elastic Search domains can be members of EC2 Security Groups. + + ``` + (ESDomain)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup) + ``` + +- Elastic Search domains belong to AWS Accounts. + + ``` + (AWSAccount)-[RESOURCE]->(ESDomain) + ``` + +- DNS Records can point to Elastic Search domains. + + ``` + (DNSRecord)-[DNS_POINTS_TO]->(ESDomain) + ``` + +### Endpoint + +Representation of a generic network endpoint. + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| protocol | The protocol of this endpoint | +| port | The port of this endpoint | + + +#### Relationships + +- Endpoints can be installed load balancers, though more specifically we would refer to these Endpoint nodes as [ELBListeners](#endpoint::elblistener). + + ``` + (LoadBalancer)-[ELB_LISTENER]->(Endpoint) + ``` + + +### Endpoint::ELBListener + +Representation of an AWS Elastic Load Balancer [Listener](https://docs.aws.amazon.com/elasticloadbalancing/latest/APIReference/API_LoadBalancer.html). Here, an ELBListener is a more specific type of Endpoint. Here'a [good introduction](https://docs.aws.amazon.com/elasticloadbalancing/2012-06-01/APIReference/Welcome.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| protocol | The protocol of this endpoint | +| port | The port of this endpoint | +| policy\_names | A list of SSL policy names set on the listener. +| **id** | The ELB ID. This is a concatenation of the DNS name, port, and protocol. | +| instance\_port | The port open on the EC2 instance that this listener is connected to | +| instance\_protocol | The protocol defined on the EC2 instance that this listener is connected to | + + +#### Relationships + +- A ELBListener is installed on a load balancer. + + ``` + (LoadBalancer)-[ELB_LISTENER]->(ELBListener) + ``` + +### Endpoint::ELBV2Listener + +Representation of an AWS Elastic Load Balancer V2 [Listener](https://docs.aws.amazon.com/elasticloadbalancing/latest/APIReference/API_Listener.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| protocol | The protocol of this endpoint - One of `'HTTP''HTTPS''TCP''TLS''UDP''TCP_UDP'` | +| port | The port of this endpoint | +| ssl\_policy | Only set for HTTPS or TLS listener. The security policy that defines which protocols and ciphers are supported. | +| targetgrouparn | The ARN of the Target Group, if the Action type is `forward`. | + + +#### Relationships + +- A ELBV2Listener is installed on a LoadBalancerV2. + + ``` + (elbv2)-[r:ELBV2_LISTENER]->(ELBV2Listener) + ``` + + +### Ip + +Represents a generic IP address. + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **ip** | The IPv4 address | +| **id** | Same as `ip` | + + +#### Relationships + +- DNSRecords can point to IP addresses. + + ``` + (DNSRecord)-[DNS_POINTS_TO]->(Ip) + ``` + + +### IpRule + +Represents a generic IP rule. The creation of this node is currently derived from ingesting AWS [EC2 Security Group](#ec2securitygroup) rules. + +| Field | Description | +|-------|-------------| +| **ruleid** | `{group_id}/{rule_type}/{from_port}{to_port}{protocol}` | +| groupid | The groupid of the EC2 Security Group that this was derived from | +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| protocol | The protocol this rule applies to | +| fromport | Lowest port in the range defined by this rule| +| toport | Highest port in the range defined by this rule| + + +#### Relationships + +- IpRules are defined from EC2SecurityGroups. + + ``` + (IpRule, IpPermissionInbound)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup) + ``` + + +### IpRule::IpPermissionInbound + +An IpPermissionInbound node is a specific type of IpRule. It represents a generic inbound IP-based rules. The creation of this node is currently derived from ingesting AWS [EC2 Security Group](#ec2securitygroup) rules. + +| Field | Description | +|-------|-------------| +| **ruleid** | `{group_id}/{rule_type}/{from_port}{to_port}{protocol}` | +| groupid | The groupid of the EC2 Security Group that this was derived from | +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| protocol | The protocol this rule applies to | +| fromport | Lowest port in the range defined by this rule| +| toport | Highest port in the range defined by this rule| + +#### Relationships + +- IpPermissionInbound rules are defined from EC2SecurityGroups. + + ``` + (IpRule, IpPermissionInbound)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup) + ``` + + +### LoadBalancer + +Represents an AWS Elastic Load Balancer. See [spec for details](https://docs.aws.amazon.com/elasticloadbalancing/2012-06-01/APIReference/API_LoadBalancerDescription.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| scheme| The type of load balancer. Valid only for load balancers in a VPC. If scheme is `internet-facing`, the load balancer has a public DNS name that resolves to a public IP address. If scheme is `internal`, the load balancer has a public DNS name that resolves to a private IP address. | +| name| The name of the load balancer| +| **dnsname** | The DNS name of the load balancer. | +| canonicalhostedzonename| The DNS name of the load balancer | +| **id** | Currently set to the `dnsname` of the load balancer. | +| region| The region of the load balancer | +|createdtime | The date and time the load balancer was created. | +|canonicalhostedzonenameid| The ID of the Amazon Route 53 hosted zone for the load balancer. | +| exposed\_internet | The `exposed_internet` flag is set to `True` when the load balancer's `scheme` field is set to `internet-facing`. This indicates that the load balancer has a public DNS name that resolves to a public IP address. | + + +#### Relationships + +- LoadBalancers can be connected to EC2Instances and therefore expose them. + + ``` + (LoadBalancer)-[EXPOSE]->(EC2Instance) + ``` + +- LoadBalancers can have [source security groups](https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-security-groups.html) configured. + + ``` + (LoadBalancer)-[SOURCE_SECURITY_GROUP]->(EC2SecurityGroup) + ``` + +- LoadBalancers can be part of EC2SecurityGroups. + + ``` + (LoadBalancer)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup) + ``` + +- LoadBalancers can be part of EC2 Subnets + + ``` + (LoadBalancer)-[SUBNET]->(EC2Subnet) + ``` + + +- LoadBalancers can be part of EC2 Subnets + + ``` + (LoadBalancer)-[PART_OF_SUBNET]->(EC2Subnet) + ``` + +- LoadBalancers can have listeners configured to accept connections from clients ([good introduction](https://docs.aws.amazon.com/elasticloadbalancing/2012-06-01/APIReference/Welcome.html)). + + ``` + (LoadBalancer)-[ELB_LISTENER]->(Endpoint, ELBListener) + ``` + +- LoadBalancers are part of AWSAccounts. + + ``` + (AWSAccount)-[RESOURCE]->(LoadBalancer) + ``` + +- AWSDNSRecords and DNSRecords point to LoadBalancers. + + ``` + (AWSDNSRecord, DNSRecord)-[DNS_POINTS_TO]->(LoadBalancer) + ``` + +### LoadBalancerV2 + +Represents an Elastic Load Balancer V2 ([Application Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/introduction.html) or [Network Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/latest/network/introduction.html).) API reference [here](https://docs.aws.amazon.com/elasticloadbalancing/latest/APIReference/API_LoadBalancer.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| scheme| The type of load balancer. If scheme is `internet-facing`, the load balancer has a public DNS name that resolves to a public IP address. If scheme is `internal`, the load balancer has a public DNS name that resolves to a private IP address. | +| name| The name of the load balancer| +| **dnsname** | The DNS name of the load balancer. | +| exposed_internet | The `exposed_internet` flag is set to `True` when the load balancer's `scheme` field is set to `internet-facing`. This indicates that the load balancer has a public DNS name that resolves to a public IP address. | +| **id** | Currently set to the `dnsname` of the load balancer. | +| type | Can be `application` or `network` | +| region| The region of the load balancer | +|createdtime | The date and time the load balancer was created. | +|canonicalhostedzonenameid| The ID of the Amazon Route 53 hosted zone for the load balancer. | + + +#### Relationships + + +- LoadBalancerV2's can be connected to EC2Instances and therefore expose them. + + ``` + (LoadBalancerV2)-[EXPOSE]->(EC2Instance) + ``` + +- LoadBalancerV2's can be part of EC2SecurityGroups but only if their `type` = "application". NLBs don't have SGs. + + ``` + (LoadBalancerV2)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup) + ``` + +- LoadBalancerV2's can be part of EC2 Subnets + + ``` + (LoadBalancerV2)-[SUBNET]->(EC2Subnet) + ``` + +- LoadBalancerV2's can be part of EC2 Subnets + + ``` + (LoadBalancerV2)-[PART_OF_SUBNET]->(EC2Subnet) + ``` + +- LoadBalancerV2's have [listeners](https://docs.aws.amazon.com/elasticloadbalancing/latest/APIReference/API_Listener.html): + + ``` + (LoadBalancerV2)-[ELBV2_LISTENER]->(ELBV2Listener) + ``` + +### Nameserver + +Represents a DNS nameserver. +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The address of the nameserver| +| name | The name or address of the nameserver| + +#### Relationships + +- Nameservers are nameservers for to DNSZone. + + ``` + (Nameserver)-[NAMESERVER]->(DNSZone) + ``` + +### NetworkInterface + +Representation of a generic Network Interface. Currently however, we only create NetworkInterface nodes from AWS [EC2 Instances](#ec2instance). The spec for an AWS EC2 network interface is [here](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_InstanceNetworkInterface.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| mac\_address| The MAC address of the network interface| +| description | Description of the network interface| +| private\_ip\_address| The primary IPv4 address of the network interface within the subnet | +| **id** | The ID of the network interface. (known as `networkInterfaceId` in EC2) | +| private\_dns\_name| The private DNS name | +| status | Status of the network interface. Valid Values: ``available \| associated \| attaching \| in-use \| detaching `` | +| subnetid | The ID of the subnet | +| interface_type | Describes the type of network interface. Valid values: `` interface \| efa `` | +| requester_id | Id of the requester, e.g. `amazon-elb` for ELBs | +| requester_managed | Indicates whether the interface is managed by the requester | +| source_dest_check | Indicates whether to validate network traffic to or from this network interface. | +| public_ip | Public IPv4 address attached to the interface | + + +#### Relationships + +- EC2 Network Interfaces belong to AWS accounts. + + (NetworkInterface)<-[:RESOURCE]->(:AWSAccount) + +- Network interfaces can be connected to EC2Subnets. + + ``` + (NetworkInterface)-[PART_OF_SUBNET]->(EC2Subnet) + ``` + +- Network interfaces can be members of EC2SecurityGroups. + + ``` + (NetworkInterface)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup) + ``` + +- EC2Instances can have NetworkInterfaces connected to them. + + ``` + (EC2Instance)-[NETWORK_INTERFACE]->(NetworkInterface) + ``` + +- LoadBalancers can have NetworkInterfaces connected to them. + + ``` + (LoadBalancer)-[NETWORK_INTERFACE]->(NetworkInterface) + ``` + +- LoadBalancerV2s can have NetworkInterfaces connected to them. + + ``` + (LoadBalancerV2)-[NETWORK_INTERFACE]->(NetworkInterface) + ``` +- EC2PrivateIps are connected to a NetworkInterface. + + ``` + (NetworkInterface)-[PRIVATE_IP_ADDRESS]->(EC2PrivateIp) + ``` +- EC2 Network Interfaces can be tagged with AWSTags. + + ``` + (NetworkInterface)-[TAGGED]->(AWSTag) + ``` + +### AWSPeeringConnection + +Representation of an AWS [PeeringConnection](https://docs.aws.amazon.com/vpc/latest/peering/what-is-vpc-peering.html) implementing an AWS [VpcPeeringConnection](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_VpcPeeringConnection.html) object. + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | vpcPeeringConnectionId, The ID of the VPC peering connection. | +| allow_dns_resolution_from_remote_vpc | Indicates whether a local VPC can resolve public DNS hostnames to private IP addresses when queried from instances in a peer VPC. | +| allow_egress_from_local_classic_link_to_remote_vpc | Indicates whether a local ClassicLink connection can communicate with the peer VPC over the VPC peering connection. | +| allow_egress_from_local_vpc_to_remote_classic_link | Indicates whether a local VPC can communicate with a ClassicLink connection in the peer VPC over the VPC peering connection. | +| requester_region | Peering requester region | +| accepter_region | Peering accepter region | +| status_code | The status of the VPC peering connection. | +| status_message | A message that provides more information about the status, if applicable. | + +#### Relationships + +- `AWSVpc` is an accepter or requester vpc. + ``` + (AWSVpc)<-[REQUESTER_VPC]-(AWSPeeringConnection) + (AWSVpc)<-[ACCEPTER_VPC]-(AWSPeeringConnection) + ``` + +- `AWSCidrBlock` is an accepter or requester cidr. + ``` + (AWSCidrBlock)<-[REQUESTER_CIDR]-(AWSPeeringConnection) + (AWSCidrBlock)<-[ACCEPTER_CIDR]-(AWSPeeringConnection) + ``` + +### RedshiftCluster + +Representation of an AWS [RedshiftCluster](https://docs.aws.amazon.com/redshift/latest/APIReference/API_Cluster.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **arn** | The Amazon Resource Name (ARN) for the Redshift cluster | +| **id** | Same as arn | +| availability\_zone | Specifies the name of the Availability Zone the cluster is located in | +| cluster\_create\_time | Provides the date and time the cluster was created | +| cluster\_identifier | The unique identifier of the cluster. | +| cluster_revision_number | The specific revision number of the database in the cluster. | +| db_name | The name of the initial database that was created when the cluster was created. This same name is returned for the life of the cluster. If an initial database was not specified, a database named devdev was created by default. | +| encrypted | Specifies whether the cluster has encryption enabled | +| cluster\_status | The current state of the cluster. | +| endpoint\_address | DNS name of the Redshift cluster endpoint | +| endpoint\_port | The port that the Redshift cluster's endpoint is listening on | +| master\_username | The master user name for the cluster. This name is used to connect to the database that is specified in the DBName parameter. | +| node_type | The node type for the nodes in the cluster. | +| number\_of\_nodes | The number of compute nodes in the cluster. | +| publicly_accessible | A boolean value that, if true, indicates that the cluster can be accessed from a public network. | +| vpc_id | The identifier of the VPC the cluster is in, if the cluster is in a VPC. | + + +#### Relationships + +- Redshift clusters are part of AWS Accounts. + + ``` + (AWSAccount)-[RESOURCE]->(RedshiftCluster) + ``` + +- Redshift clusters can be members of EC2 Security Groups. + + ``` + (RedshiftCluster)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup) + ``` + +- Redshift clusters may assume IAM roles. See [this article](https://docs.aws.amazon.com/redshift/latest/mgmt/authorizing-redshift-service.html). + + ``` + (RedshiftCluster)-[STS_ASSUMEROLE_ALLOW]->(AWSPrincipal) + ``` + +- Redshift clusters can be members of AWSVpcs. + + ``` + (RedshiftCluster)-[MEMBER_OF_AWS_VPC]->(AWSVpc) + ``` + +### RDSCluster + +Representation of an AWS Relational Database Service [DBCluster](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DBCluster.html) + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | Same as ARN | +| **arn** | The Amazon Resource Name (ARN) for the DB cluster. | +| **allocated\_storage** | For all database engines except Amazon Aurora, AllocatedStorage specifies the allocated storage size in gibibytes (GiB). For Aurora, AllocatedStorage always returns 1, because Aurora DB cluster storage size isn't fixed, but instead automatically adjusts as needed. | +| **availability\_zones** | Provides the list of Availability Zones (AZs) where instances in the DB cluster can be created. | +| **backup\_retention\_period** | Specifies the number of days for which automatic DB snapshots are retained. | +| **character\_set\_name** | If present, specifies the name of the character set that this cluster is associated with. | +| **database\_name** | Contains the name of the initial database of this DB cluster that was provided at create time, if one was specified when the DB cluster was created. This same name is returned for the life of the DB cluster. | +| **db\_cluster\_identifier** | Contains a user-supplied DB cluster identifier. This identifier is the unique key that identifies a DB cluster. | +| **db\_parameter\_group** | Specifies the name of the DB cluster parameter group for the DB cluster. | +| **status** | Specifies the current state of this DB cluster. | +| **earliest\_restorable\_time** | The earliest time to which a database can be restored with point-in-time restore. | +| **endpoint** | Specifies the connection endpoint for the primary instance of the DB cluster. | +| **reader\_endpoint** | The reader endpoint for the DB cluster. The reader endpoint for a DB cluster load-balances connections across the Aurora Replicas that are available in a DB cluster. As clients request new connections to the reader endpoint, Aurora distributes the connection requests among the Aurora Replicas in the DB cluster. This functionality can help balance your read workload across multiple Aurora Replicas in your DB cluster. If a failover occurs, and the Aurora Replica that you are connected to is promoted to be the primary instance, your connection is dropped. To continue sending your read workload to other Aurora Replicas in the cluster, you can then reconnect to the reader endpoint. | +| **multi\_az** | Specifies whether the DB cluster has instances in multiple Availability Zones. | +| **engine** | The name of the database engine to be used for this DB cluster. | +| **engine\_version** | Indicates the database engine version. | +| **latest\_restorable\_time** | Specifies the latest time to which a database can be restored with point-in-time restore. | +| **port** | Specifies the port that the database engine is listening on. | +| **master\_username** | Contains the master username for the DB cluster. | +| **preferred\_backup\_window** | Specifies the daily time range during which automated backups are created if automated backups are enabled, as determined by the BackupRetentionPeriod. | +| **preferred\_maintenance\_window** | Specifies the weekly time range during which system maintenance can occur, in Universal Coordinated Time (UTC). | +| **hosted\_zone\_id** | Specifies the ID that Amazon Route 53 assigns when you create a hosted zone. | +| **storage\_encrypted** | Specifies whether the DB cluster is encrypted. | +| **kms\_key\_id** | If StorageEncrypted is enabled, the AWS KMS key identifier for the encrypted DB cluster. The AWS KMS key identifier is the key ARN, key ID, alias ARN, or alias name for the AWS KMS customer master key (CMK). | +| **db\_cluster\_resource\_id** | The AWS Region-unique, immutable identifier for the DB cluster. This identifier is found in AWS CloudTrail log entries whenever the AWS KMS CMK for the DB cluster is accessed. | +| **clone\_group\_id** | Identifies the clone group to which the DB cluster is associated. | +| **cluster\_create\_time** | Specifies the time when the DB cluster was created, in Universal Coordinated Time (UTC). | +| **earliest\_backtrack\_time** | The earliest time to which a DB cluster can be backtracked. | +| **backtrack\_window** | The target backtrack window, in seconds. If this value is set to 0, backtracking is disabled for the DB cluster. Otherwise, backtracking is enabled. | +| **backtrack\_consumed\_change\_records** | The number of change records stored for Backtrack. | +| **capacity** | The current capacity of an Aurora Serverless DB cluster. The capacity is 0 (zero) when the cluster is paused. | +| **engine\_mode** | The DB engine mode of the DB cluster, either provisioned, serverless, parallelquery, global, or multimaster. | +| **scaling\_configuration\_info\_min\_capacity** | The minimum capacity for the Aurora DB cluster in serverless DB engine mode. | +| **scaling\_configuration\_info\_max\_capacity** | The maximum capacity for an Aurora DB cluster in serverless DB engine mode. | +| **scaling\_configuration\_info\_auto\_pause** | A value that indicates whether automatic pause is allowed for the Aurora DB cluster in serverless DB engine mode. | +| **deletion\_protection** | Indicates if the DB cluster has deletion protection enabled. The database can't be deleted when deletion protection is enabled. | + +#### Relationships + +- RDS Clusters are part of AWS Accounts. + + ``` + (AWSAccount)-[RESOURCE]->(RDSCluster) + ``` + +- Some RDS instances are cluster members. + + ``` + (replica:RDSInstance)-[IS_CLUSTER_MEMBER_OF]->(source:RDSCluster) + ``` + +### RDSInstance + +Representation of an AWS Relational Database Service [DBInstance](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DBInstance.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | Same as ARN | +| **arn** | The Amazon Resource Name (ARN) for the DB instance. | +| **db\_instance_identifier** | Contains a user-supplied database identifier. This identifier is the unique key that identifies a DB instance. | +| availability\_zone | Specifies the name of the Availability Zone the DB instance is located in. | +| backup\_retention\_period | Specifies the number of days for which automatic DB snapshots are retained. | +| preferred\_backup\_window | Specifies the daily time range during which automated backups are created if automated backups are enabled, as determined by the BackupRetentionPeriod. | +| ca\_certificate\_identifier | The identifier of the CA certificate for this DB instance. | +| db\_cluster\_identifier | If the DB instance is a member of a DB cluster, contains the name of the DB cluster that the DB instance is a member of. | +| db\_instance\_class | Contains the name of the compute and memory capacity class of the DB instance. | +| db\_instance\_port | Specifies the port that the DB instance listens on. | +| dbi\_resource\_id | The AWS Region-unique, immutable identifier for the DB instance. This identifier is found in AWS CloudTrail log entries whenever the AWS KMS key for the DB instance is accessed. | +| db\_name | The meaning of this parameter differs according to the database engine you use. For example, this value returns MySQL, MariaDB, or PostgreSQL information when returning values from CreateDBInstanceReadReplica since Read Replicas are only supported for these engines.

**MySQL, MariaDB, SQL Server, PostgreSQL:** Contains the name of the initial database of this instance that was provided at create time, if one was specified when the DB instance was created. This same name is returned for the life of the DB instance.

**Oracle:** Contains the Oracle System ID (SID) of the created DB instance. Not shown when the returned parameters do not apply to an Oracle DB instance. | +| engine | Provides the name of the database engine to be used for this DB instance. | +| engine\_version | Indicates the database engine version. | +| enhanced\_monitoring\_resource\_arn | The Amazon Resource Name (ARN) of the Amazon CloudWatch Logs log stream that receives the Enhanced Monitoring metrics data for the DB instance. | +| instance\_create\_time | Provides the date and time the DB instance was created. | +| kms\_key\_id | If StorageEncrypted is true, the AWS KMS key identifier for the encrypted DB instance. | +| master\_username | Contains the master username for the DB instance. | +| monitoring\_role\_arn | The ARN for the IAM role that permits RDS to send Enhanced Monitoring metrics to Amazon CloudWatch Logs. | +| multi\_az | Specifies if the DB instance is a Multi-AZ deployment. | +| performance\_insights\_enabled | True if Performance Insights is enabled for the DB instance, and otherwise false. | +| preferred\_maintenance\_window | Specifies the weekly time range during which system maintenance can occur, in Universal Coordinated Time (UTC). | +| publicly\_accessible | Specifies the accessibility options for the DB instance. A value of true specifies an Internet-facing instance with a publicly resolvable DNS name, which resolves to a public IP address. A value of false specifies an internal instance with a DNS name that resolves to a private IP address. | +| storage\_encrypted | Specifies whether the DB instance is encrypted. | +| endpoint\_address | DNS name of the RDS instance| +| endpoint\_port | The port that the RDS instance is listening on | +| endpoint\_hostedzoneid | The AWS DNS Zone ID that is associated with the RDS instance's DNS entry | +| auto\_minor\_version\_upgrade | Specifies whether minor version upgrades are applied automatically to the DB instance during the maintenance window | +| iam\_database\_authentication\_enabled | Specifies if mapping of AWS Identity and Access Management (IAM) accounts to database accounts is enabled | + + + +#### Relationships + +- RDS Instances are part of AWS Accounts. + + ``` + (AWSAccount)-[RESOURCE]->(RDSInstance) + ``` + +- Some RDS instances are Read Replicas. + + ``` + (replica:RDSInstance)-[IS_READ_REPLICA_OF]->(source:RDSInstance) + ``` + +- RDS Instances can be members of EC2 Security Groups. + + ``` + (RDSInstance)-[m:MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup) + ``` + +- RDS Instances are connected to DB Subnet Groups. + + ``` + (RDSInstance)-[:MEMBER_OF_DB_SUBNET_GROUP]->(DBSubnetGroup) + ``` + +- RDS Instances can be tagged with AWSTags. + + ``` + (RDSInstance)-[TAGGED]->(AWSTag) + ``` + +### RDSSnapshot + +Representation of an AWS Relational Database Service [DBSnapshot](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DBSnapshot.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | Same as ARN | +| **arn** | The Amazon Resource Name (ARN) for the DB snapshot. | +| **db\_snapshot\_identifier** | Specifies the identifier for the DB snapshot. | +| db\_instance\_identifier | Specifies the DB instance identifier of the DB instance this DB snapshot was created from. | +| snapshot\_create\_time | Specifies when the snapshot was taken in Coordinated Universal Time (UTC). Changes for the copy when the snapshot is copied. | +| engine | Specifies the name of the database engine. | +| allocated\_storage | Specifies the allocated storage size in gibibytes (GiB). | +| status | Specifies the status of this DB snapshot. | +| port | Specifies the port that the database engine was listening on at the time of the snapshot. | +| availability\_zone | Specifies the name of the Availability Zone the DB instance was located in at the time of the DB snapshot. | +| vpc\_id | Provides the VPC ID associated with the DB snapshot. | +| instance\_create\_time | Specifies the time in Coordinated Universal Time (UTC) when the DB instance, from which the snapshot was taken, was created. | +| master\_username | Provides the master username for the DB snapshot. | +| engine\_version | Specifies the version of the database engine. | +| license\_model | License model information for the restored DB instance. | +| snapshot\_type | Provides the type of the DB snapshot. | +| iops | Specifies the Provisioned IOPS (I/O operations per second) value of the DB instance at the time of the snapshot. | +| option\_group\_name | Provides the option group name for the DB snapshot. | +| percent\_progress | The percentage of the estimated data that has been transferred. | +| source\_region | The AWS Region that the DB snapshot was created in or copied from. | +| source\_db\_snapshot\_identifier | The DB snapshot Amazon Resource Name (ARN) that the DB snapshot was copied from. It only has a value in the case of a cross-account or cross-Region copy. | +| storage\_type | Specifies the storage type associated with DB snapshot. | +| tde\_credential\_arn | The ARN from the key store with which to associate the instance for TDE encryption. | +| encrypted | Specifies whether the DB snapshot is encrypted. | +| kms\_key\_id | If Encrypted is true, the AWS KMS key identifier for the encrypted DB snapshot. The AWS KMS key identifier is the key ARN, key ID, alias ARN, or alias name for the KMS key. | +| timezone | The time zone of the DB snapshot. In most cases, the Timezone element is empty. Timezone content appears only for snapshots taken from Microsoft SQL Server DB instances that were created with a time zone specified. | +| iam\_database\_authentication\_enabled | True if mapping of AWS Identity and Access Management (IAM) accounts to database accounts is enabled, and otherwise false. | +| processor\_features | The number of CPU cores and the number of threads per core for the DB instance class of the DB instance when the DB snapshot was created. | +| dbi\_resource\_id | The identifier for the source DB instance, which can't be changed and which is unique to an AWS Region. | +| original\_snapshot\_create\_time | Specifies the time of the CreateDBSnapshot operation in Coordinated Universal Time (UTC). Doesn't change when the snapshot is copied. | +| snapshot\_database\_time | The timestamp of the most recent transaction applied to the database that you're backing up. Thus, if you restore a snapshot, SnapshotDatabaseTime is the most recent transaction in the restored DB instance. In contrast, originalSnapshotCreateTime specifies the system time that the snapshot completed. If you back up a read replica, you can determine the replica lag by comparing SnapshotDatabaseTime with originalSnapshotCreateTime. For example, if originalSnapshotCreateTime is two hours later than SnapshotDatabaseTime, then the replica lag is two hours. | +| snapshot\_target | Specifies where manual snapshots are stored: AWS Outposts or the AWS Region. | +| storage\_throughput | | +| region | The AWS region of the snapshot | + + + +#### Relationships + +- RDS Snapshots are part of AWS Accounts. + + ``` + (AWSAccount)-[RESOURCE]->(RDSSnapshot) + ``` + +- RDS Snapshots are connected to DB Instances. + + ``` + (RDSSnapshot)-[:IS_SNAPSHOT_SOURCE]->(RDSInstance) + ``` + +- RDS Snapshots can be tagged with AWSTags. + + ``` + (RDSSnapshot)-[TAGGED]->(AWSTag) + ``` + +### S3Acl + +Representation of an AWS S3 [Access Control List](https://docs.aws.amazon.com/AmazonS3/latest/API/API_control_S3AccessControlList.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| granteeid | The ID of the grantee as defined [here](https://docs.aws.amazon.com/AmazonS3/latest/API/API_control_S3Grantee.html) | +| displayname | Optional display name for the ACL | +| permission | Valid values: ``FULL_CONTROL \| READ \| WRITE \| READ_ACP \| WRITE_ACP`` (ACP = Access Control Policy)| +| **id** | The ID of this ACL| +| type | The type of the [grantee](https://docs.aws.amazon.com/AmazonS3/latest/API/API_Grantee.html). Either ``CanonicalUser \| AmazonCustomerByEmail \| Group``. | +| ownerid| The ACL's owner ID as defined [here](https://docs.aws.amazon.com/AmazonS3/latest/API/API_control_S3ObjectOwner.html)| + + +#### Relationships + + +- S3 Access Control Lists apply to S3 buckets. + + ``` + (S3Acl)-[APPLIES_TO]->(S3Bucket) + ``` + +### S3Bucket + +Representation of an AWS S3 [Bucket](https://docs.aws.amazon.com/AmazonS3/latest/API/API_Bucket.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| creationdate | Date-time when the bucket was created | +| **id** | Same as `name`, as seen below | +| name | The name of the bucket. This is guaranteed to be [globally unique](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.list_buckets) | +| anonymous\_actions | List of anonymous internet accessible actions that may be run on the bucket. This list is taken by running [policyuniverse](https://github.com/Netflix-Skunkworks/policyuniverse#internet-accessible-policy) on the policy that applies to the bucket. | +| anonymous\_access | True if this bucket has a policy applied to it that allows anonymous access or if it is open to the internet. These policy determinations are made by using the [policyuniverse](https://github.com/Netflix-Skunkworks/policyuniverse) library. | +| region | The region that the bucket is in. Only defined if the S3 bucket has a [location constraint](https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html#access-bucket-intro) | +| default\_encryption | True if this bucket has [default encryption](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-encryption.html) enabled. | +| encryption\_algorithm | The encryption algorithm used for default encryption. Only defined if the S3 bucket has default encryption enabled. | +| encryption\_key\_id | The KMS key ID used for default encryption. Only defined if the S3 bucket has SSE-KMS enabled as the default encryption method. | +| bucket\_key\_enabled | True if a bucket key is enabled, when using SSE-KMS as the default encryption method. | +| versioning\_status | The versioning state of the bucket. | +| mfa\_delete | Specifies whether MFA delete is enabled in the bucket versioning configuration. | +| block\_public\_acls | Specifies whether Amazon S3 should block public access control lists (ACLs) for this bucket and objects in this bucket. | +| ignore\_public\_acls | Specifies whether Amazon S3 should ignore public ACLs for this bucket and objects in this bucket. | +| block\_public\_acls | Specifies whether Amazon S3 should block public bucket policies for this bucket. | +| restrict\_public\_buckets | Specifies whether Amazon S3 should restrict public bucket policies for this bucket. | + +#### Relationships + +- S3Buckets are resources in an AWS Account. + + ``` + (AWSAccount)-[RESOURCE]->(S3Bucket) + ``` + +- S3 Access Control Lists apply to S3 buckets. + + ``` + (S3Acl)-[APPLIES_TO]->(S3Bucket) + ``` + +- S3 Buckets can be tagged with AWSTags. + + ``` + (S3Bucket)-[TAGGED]->(AWSTag) + ``` + +### S3PolicyStatement + +Representation of an AWS S3 [Bucket Policy Statements](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-policies.html) for controlling ownership of objects and ACLs of the bucket. + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| policy_id | Optional string "Id" for the bucket's policy | +| policy_version| Version of the bucket's policy | +| **id** | The unique identifier for a bucket policy statement.
If the statement has an Sid the id will be calculated as _S3Bucket.id_/policy_statement/_index of statement in statement_/_Sid_.
If the statement has no Sid the id will be calculated as _S3Bucket.id_/policy_statement/_index of statement in statement_/ | +| effect | Specifies "Deny" or "Allow" for the policy statement | +| action | Specifies permissions that policy statement applies to, as defined [here](https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html) | +| resource | Specifies the resource the bucket policy statement is based on | +| condition | Specifies conditions where permissions are granted: [examples](https://docs.aws.amazon.com/AmazonS3/latest/userguide/amazon-s3-policy-keys.html) | +| sid | Optional string to label the specific bucket policy statement | + +#### Relationships + +- S3PolicyStatements define the policy for S3 Buckets. + + ``` + (:S3Bucket)-[:POLICY_STATEMENT]->(:S3PolicyStatement) + ``` + + +### KMSKey + +Representation of an AWS [KMS Key](https://docs.aws.amazon.com/kms/latest/APIReference/API_KeyListEntry.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The id of the key| +| name | The name of the key | +| description | The description of the key | +| enabled | Whether the key is enabled | +| region | The region where key is created| +| anonymous\_actions | List of anonymous internet accessible actions that may be run on the key. | +| anonymous\_access | True if this key has a policy applied to it that allows anonymous access or if it is open to the internet. | + +#### Relationships + +- AWS KMS Keys are resources in an AWS Account. + + ``` + (AWSAccount)-[RESOURCE]->(KMSKey) + ``` + +- AWS KMS Key may also be refered as KMSAlias via aliases. + + ``` + (KMSKey)-[KNOWN_AS]->(KMSAlias) + ``` + +- AWS KMS Key may also have KMSGrant based on grants. + + ``` + (KMSGrant)-[APPLIED_ON]->(KMSKey) + ``` + +### KMSAlias + +Representation of an AWS [KMS Key Alias](https://docs.aws.amazon.com/kms/latest/APIReference/API_AliasListEntry.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The arn of the alias| +| aliasname | The name of the alias | +| targetkeyid | The kms key id associated via this alias | + +#### Relationships + +- AWS KMS Key may also be refered as KMSAlias via aliases. + + ``` + (KMSKey)-[KNOWN_AS]->(KMSAlias) + ``` + +### KMSGrant + +Representation of an AWS [KMS Key Grant](https://docs.aws.amazon.com/kms/latest/APIReference/API_GrantListEntry.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The id of the key grant| +| name | The name of the key grant | +| granteeprincipal | The principal associated with the key grant | +| creationdate | ISO 8601 date-time string when the grant was created | + +#### Relationships + +- AWS KMS Key may also have KMSGrant based on grants. + + ``` + (KMSGrant)-[APPLIED_ON]->(KMSKey) + ``` + +### APIGatewayRestAPI + +Representation of an AWS [API Gateway REST API](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-rest-api.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The id of the REST API| +| createddate | The timestamp when the REST API was created | +| version | The version identifier for the API | +| minimumcompressionsize | A nullable integer that is used to enable or disable the compression of the REST API | +| disableexecuteapiendpoint | Specifies whether clients can invoke your API by using the default `execute-api` endpoint | +| region | The region where the REST API is created | +| anonymous\_actions | List of anonymous internet accessible actions that may be run on the API. | +| anonymous\_access | True if this API has a policy applied to it that allows anonymous access or if it is open to the internet. | + +#### Relationships + +- AWS API Gateway REST APIs are resources in an AWS Account. + + ``` + (AWSAccount)-[RESOURCE]->(APIGatewayRestAPI) + ``` + +- AWS API Gateway REST APIs may be associated with an API Gateway Stage. + + ``` + (APIGatewayRestAPI)-[ASSOCIATED_WITH]->(APIGatewayStage) + ``` + +- AWS API Gateway REST APIs may also have API Gateway Resource resources. + + ``` + (APIGatewayRestAPI)-[RESOURCE]->(APIGatewayResource) + ``` + +### APIGatewayStage + +Representation of an AWS [API Gateway Stage](https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-stages.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The name of the API Gateway Stage| +| createddate | The timestamp when the stage was created | +| deploymentid | The identifier of the Deployment that the stage points to. | +| clientcertificateid | The identifier of a client certificate for an API stage. | +| cacheclusterenabled | Specifies whether a cache cluster is enabled for the stage. | +| cacheclusterstatus | The status of the cache cluster for the stage, if enabled. | +| tracingenabled | Specifies whether active tracing with X-ray is enabled for the Stage | +| webaclarn | The ARN of the WebAcl associated with the Stage | + +#### Relationships + +- AWS API Gateway REST APIs may be associated with an API Gateway Stage. + + ``` + (APIGatewayRestAPI)-[ASSOCIATED_WITH]->(APIGatewayStage) + ``` + +- AWS API Gateway Stage may also contain a Client Certificate. + + ``` + (APIGatewayStage)-[HAS_CERTIFICATE]->(APIGatewayClientCertificate) + ``` + +### APIGatewayClientCertificate + +Representation of an AWS [API Gateway Client Certificate](https://docs.aws.amazon.com/apigateway/api-reference/resource/client-certificate/). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The identifier of the client certificate | +| createddate | The timestamp when the client certificate was created | +| expirationdate | The timestamp when the client certificate will expire | + +#### Relationships + +- AWS API Gateway Stage may also contain a Client Certificate. + + ``` + (APIGatewayStage)-[HAS_CERTIFICATE]->(APIGatewayClientCertificate) + ``` + +### APIGatewayResource + +Representation of an AWS [API Gateway Resource](https://docs.aws.amazon.com/apigateway/api-reference/resource/resource/). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The id of the REST API| +| path | The timestamp when the REST API was created | +| pathpart | The version identifier for the API | +| parentid | A nullable integer that is used to enable or disable the compression of the REST API | + +#### Relationships + +- AWS API Gateway REST APIs may also have API Gateway Resource resources. + + ``` + (APIGatewayRestAPI)-[RESOURCE]->(APIGatewayResource) + ``` + +### AutoScalingGroup + +Representation of an AWS [Auto Scaling Group Resource](https://docs.aws.amazon.com/autoscaling/ec2/userguide/AutoScalingGroup.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **arn** | The ARN of the Auto Scaling Group| +| name | The name of the Auto Scaling group. | +| createdtime | The date and time the group was created. | +| launchconfigurationname | The name of the associated launch configuration. | +| launchtemplatename | The name of the launch template. | +| launchtemplateid | The ID of the launch template. | +| launchtemplateversion | The version number of the launch template. | +| maxsize | The maximum size of the group.| +| minsize | The minimum size of the group.| +| defaultcooldown | The duration of the default cooldown period, in seconds. | +| desiredcapacity | The desired size of the group. | +| healthchecktype | The service to use for the health checks. | +| healthcheckgraceperiod | The amount of time, in seconds, that Amazon EC2 Auto Scaling waits before checking the health status of an EC2 instance that has come into service.| +| status | The current state of the group when the DeleteAutoScalingGroup operation is in progress. | +| newinstancesprotectedfromscalein | Indicates whether newly launched instances are protected from termination by Amazon EC2 Auto Scaling when scaling in.| +| maxinstancelifetime | The maximum amount of time, in seconds, that an instance can be in service. | +| capacityrebalance | Indicates whether Capacity Rebalancing is enabled. | +| region | The region of the auto scaling group. | + + +[Link to API Documentation](https://docs.aws.amazon.com/autoscaling/ec2/APIReference/API_AutoScalingGroup.html) of AWS Auto Scaling Groups + +#### Relationships + +- AWS Auto Scaling Groups are a resource under the AWS Account. + + ``` + (AWSAccount)-[RESOURCE]->(AutoScalingGroup) + ``` +- AWS Auto Scaling Groups has one or more subnets/vpc identifiers. + + ``` + (AutoScalingGroup)-[VPC_IDENTIFIER]->(EC2Subnet) + ``` +- AWS EC2 Instances are members of one or more AWS Auto Scaling Groups. + + ``` + (EC2Instance)-[MEMBER_AUTO_SCALE_GROUP]->(AutoScalingGroup) + ``` +- AWS Auto Scaling Groups have Launch Configurations + + ``` + (AutoScalingGroup)-[HAS_LAUNCH_CONFIG]->(LaunchConfiguration) + ``` +- AWS Auto Scaling Groups have Launch Templates + + ``` + (AutoScalingGroup)-[HAS_LAUNCH_TEMPLATE]->(LaunchTemplate) + ``` + +### EC2Image + +Representation of an AWS [EC2 Images (AMIs)](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The ID of the AMI.| +| name | The name of the AMI that was provided during image creation. | +| creationdate | The date and time the image was created. | +| architecture | The architecture of the image. | +| location | The location of the AMI.| +| type | The type of image.| +| ispublic | Indicates whether the image has public launch permissions. | +| platform | This value is set to `windows` for Windows AMIs; otherwise, it is blank. | +| usageoperation | The operation of the Amazon EC2 instance and the billing code that is associated with the AMI. | +| state | The current state of the AMI.| +| description | The description of the AMI that was provided during image creation.| +| enasupport | Specifies whether enhanced networking with ENA is enabled.| +| hypervisor | The hypervisor type of the image.| +| rootdevicename | The device name of the root device volume (for example, `/dev/sda1` ). | +| rootdevicetype | The type of root device used by the AMI. | +| virtualizationtype | The type of virtualization of the AMI. | +| bootmode | The boot mode of the image. | +| region | The region of the image. | + + +[Link to API Documentation](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_Image.html) of EC2 Images + +#### Relationships + +- AWS EC2 Images (AMIs) are a resource under the AWS Account. + + ``` + (AWSAccount)-[RESOURCE]->(EC2Image) + ``` + +### EC2ReservedInstance + +Representation of an AWS [EC2 Reserved Instance](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-reserved-instances.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The ID of the Reserved Instance.| +| availabilityzone | The Availability Zone in which the Reserved Instance can be used. | +| duration | The duration of the Reserved Instance, in seconds. | +| end | The time when the Reserved Instance expires. | +| start | The date and time the Reserved Instance started.| +| count | The number of reservations purchased.| +| type | The instance type on which the Reserved Instance can be used. | +| productdescription | The Reserved Instance product platform description. | +| state | The state of the Reserved Instance purchase. | +| currencycode | The currency of the Reserved Instance. It's specified using ISO 4217 standard currency codes.| +| instancetenancy | The tenancy of the instance.| +| offeringclass | The offering class of the Reserved Instance.| +| offeringtype | The Reserved Instance offering type.| +| scope | The scope of the Reserved Instance.| +| fixedprice | The purchase price of the Reserved Instance. | +| region | The region of the reserved instance. | + +#### Relationships + +- AWS EC2 Reserved Instances are a resource under the AWS Account. + + ``` + (AWSAccount)-[RESOURCE]->(EC2ReservedInstance) + ``` + +### SecretsManagerSecret + +Representation of an AWS [Secrets Manager Secret](https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_SecretListEntry.html) + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The arn of the secret. | +| created\_date | The date and time when a secret was created. | +| deleted\_date | The date and time the deletion of the secret occurred. Not present on active secrets. The secret can be recovered until the number of days in the recovery window has passed, as specified in the RecoveryWindowInDays parameter of the DeleteSecret operation. | +| description | The user-provided description of the secret. | +| kms\_key\_id | The ARN or alias of the AWS KMS customer master key (CMK) used to encrypt the SecretString and SecretBinary fields in each version of the secret. If you don't provide a key, then Secrets Manager defaults to encrypting the secret fields with the default KMS CMK, the key named awssecretsmanager, for this account. | +| last\_accessed\_date | The last date that this secret was accessed. This value is truncated to midnight of the date and therefore shows only the date, not the time. | +| last\_changed\_date | The last date and time that this secret was modified in any way. | +| last\_rotated\_date | The most recent date and time that the Secrets Manager rotation process was successfully completed. This value is null if the secret hasn't ever rotated. | +| name | The friendly name of the secret. You can use forward slashes in the name to represent a path hierarchy. For example, /prod/databases/dbserver1 could represent the secret for a server named dbserver1 in the folder databases in the folder prod. | +| owning\_service | Returns the name of the service that created the secret. | +| primary\_region | The Region where Secrets Manager originated the secret. | +| rotation\_enabled | Indicates whether automatic, scheduled rotation is enabled for this secret. | +| rotation\_lambda\_arn | The ARN of an AWS Lambda function invoked by Secrets Manager to rotate and expire the secret either automatically per the schedule or manually by a call to RotateSecret. | +| rotation\_rules\_automatically\_after\_days | Specifies the number of days between automatic scheduled rotations of the secret. | + +#### Relationships + +- AWS Secrets Manager Secrets are a resource under the AWS Account. + + ``` + (AWSAccount)-[RESOURCE]->(SecretsManagerSecret) + ``` + +### EBSVolume + +Representation of an AWS [EBS Volume](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-volumes.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The ID of the EBS Volume.| +| availabilityzone | The Availability Zone for the volume. | +| createtime | The time stamp when volume creation was initiated. | +| encrypted | Indicates whether the volume is encrypted. | +| size | The size of the volume, in GiBs.| +| state | The volume state.| +| outpostarn | The Amazon Resource Name (ARN) of the Outpost. | +| snapshotid | The snapshot ID. | +| iops | The number of I/O operations per second (IOPS). | +| type | The volume type.| +| fastrestored | Indicates whether the volume was created using fast snapshot restore.| +| multiattachenabled |Indicates whether Amazon EBS Multi-Attach is enabled.| +| throughput | The throughput that the volume supports, in MiB/s.| +| kmskeyid | The Amazon Resource Name (ARN) of the AWS Key Management Service (AWS KMS) customer master key (CMK) that was used to protect the volume encryption key for the volume.| +| deleteontermination | Indicates whether the volume is deleted on instance termination. | +| region | The region of the volume. | + +#### Relationships + +- AWS EBS Volumes are a resource under the AWS Account. + + ``` + (AWSAccount)-[RESOURCE]->(EBSVolume) + ``` + +- AWS EBS Snapshots are created using EBS Volumes + + ``` + (EBSSnapshot)-[CREATED_FROM]->(EBSVolume) + ``` + +- AWS EBS Volumes are attached to an EC2 Instance + + ``` + (EBSVolume)-[ATTACHED_TO_EC2_INSTANCE]->(EC2Instance) + ``` + +- `AWSTag` + ``` + (EBSVolume)-[TAGGED]->(AWSTag) + ``` + +### EBSSnapshot + +Representation of an AWS [EBS Snapshot](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSSnapshots.html). + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The ID of the EBS Snapshot.| +| description | The description of the snapshot. | +| progress | The progress of the snapshot, as a percentage. | +| encrypted |Indicates whether the snapshot is encrypted. | +| starttime | The time stamp when the snapshot was initiated.| +| state | The snapshot state.| +| statemessage | Encrypted Amazon EBS snapshots are copied asynchronously. If a snapshot copy operation fails (for example, if the proper AWS Key Management Service (AWS KMS) permissions are not obtained) this field displays error state details to help you diagnose why the error occurred. This parameter is only returned by DescribeSnapshots .| +| volumeid | The volume ID. | +| volumesize | The size of the volume, in GiB.| +| outpostarn | The ARN of the AWS Outpost on which the snapshot is stored. | +| dataencryptionkeyid | The data encryption key identifier for the snapshot.| +| kmskeyid | The Amazon Resource Name (ARN) of the AWS Key Management Service (AWS KMS) customer master key (CMK) that was used to protect the volume encryption key for the parent volume.| +| region | The region of the snapshot. | + +#### Relationships + +- AWS EBS Snapshots are a resource under the AWS Account. + + ``` + (AWSAccount)-[RESOURCE]->(EBSSnapshot) + ``` + +- AWS EBS Snapshots are created using EBS Volumes + + ``` + (EBSSnapshot)-[CREATED_FROM]->(EBSVolume) + ``` + +### SQSQueue + +Representation of an AWS [SQS Queue](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_GetQueueAttributes.html) + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The arn of the sqs queue. | +| created\_timestamp | The time when the queue was created in seconds | +| delay\_seconds | The default delay on the queue in seconds. | +| last\_modified\_timestamp | The time when the queue was last changed in seconds. | +| maximum\_message\_size | The limit of how many bytes a message can contain before Amazon SQS rejects it. | +| message\_retention\_period | he length of time, in seconds, for which Amazon SQS retains a message. | +| policy | The IAM policy of the queue. | +| arn | The arn of the sqs queue. | +| receive\_message\_wait\_time\_seconds | The length of time, in seconds, for which the ReceiveMessage action waits for a message to arrive. | +| redrive\_policy\_dead\_letter\_target\_arn | The Amazon Resource Name (ARN) of the dead-letter queue to which Amazon SQS moves messages after the value of maxReceiveCount is exceeded. | +| redrive\_policy\_max\_receive\_count | The number of times a message is delivered to the source queue before being moved to the dead-letter queue. When the ReceiveCount for a message exceeds the maxReceiveCount for a queue, Amazon SQS moves the message to the dead-letter-queue. | +| visibility\_timeout | The visibility timeout for the queue. | +| kms\_master\_key\_id | The ID of an AWS managed customer master key (CMK) for Amazon SQS or a custom CMK. | +| kms\_data\_key\_reuse\_period\_seconds | The length of time, in seconds, for which Amazon SQS can reuse a data key to encrypt or decrypt messages before calling AWS KMS again. | +| fifo\_queue | Whether or not the queue is FIFO. | +| content\_based\_deduplication | Whether or not content-based deduplication is enabled for the queue. | +| deduplication\_scope | Specifies whether message deduplication occurs at the message group or queue level. | +| fifo\_throughput\_limit | Specifies whether the FIFO queue throughput quota applies to the entire queue or per message group. | + +#### Relationships + +- AWS SQS Queues are a resource under the AWS Account. + + ``` + (AWSAccount)-[RESOURCE]->(SQSQueue) + ``` + +- AWS SQS Queues can have other SQS Queues configured as dead letter queues + + ``` + (SQSQueue)-[HAS_DEADLETTER_QUEUE]->(SQSQueue) + ``` + +### SecurityHub + +Representation of the configuration of AWS [Security Hub](https://docs.aws.amazon.com/securityhub/1.0/APIReference/API_DescribeHub.html) + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The arn of the hub resource. | +| subscribed\_at | The date and time when Security Hub was enabled in the account. | +| auto\_enable\_controls | Whether to automatically enable new controls when they are added to standards that are enabled. | + +#### Relationships + +- AWS Security Hub nodes are a resource under the AWS Account. + + ``` + (AWSAccount)-[RESOURCE]->(SecurityHub) + ``` + +### AWSConfigurationRecorder + +Representation of an AWS [Config Configuration Recorder](https://docs.aws.amazon.com/config/latest/APIReference/API_ConfigurationRecorder.html) + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | A combination of name:account\_id:region | +| name | The name of the recorder. | +| role\_arn | Amazon Resource Name (ARN) of the IAM role used to describe the AWS resources associated with the account. | +| recording\_group\_all\_supported | Specifies whether AWS Config records configuration changes for every supported type of regional resource. | +| recording\_group\_include\_global\_resource\_types | Specifies whether AWS Config includes all supported types of global resources (for example, IAM resources) with the resources that it records. | +| recording\_group\_resource\_types | A comma-separated list that specifies the types of AWS resources for which AWS Config records configuration changes (for example, AWS::EC2::Instance or AWS::CloudTrail::Trail). | +| region | The region of the configuration recorder. | + +#### Relationships + +- AWS Configuration Recorders are a resource under the AWS Account. + + ``` + (AWSAccount)-[RESOURCE]->(AWSConfigurationRecorder) + ``` + +### AWSConfigDeliveryChannel + +Representation of an AWS [Config Delivery Channel](https://docs.aws.amazon.com/config/latest/APIReference/API_DeliveryChannel.html) + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | A combination of name:account\_id:region | +| name | The name of the delivery channel. | +| s3\_bucket\_name | The name of the Amazon S3 bucket to which AWS Config delivers configuration snapshots and configuration history files. | +| s3\_key\_prefix | The prefix for the specified Amazon S3 bucket. | +| s3\_kms\_key\_arn | The Amazon Resource Name (ARN) of the AWS Key Management Service (KMS) customer managed key (CMK) used to encrypt objects delivered by AWS Config. Must belong to the same Region as the destination S3 bucket. | +| sns\_topic\_arn | The Amazon Resource Name (ARN) of the Amazon SNS topic to which AWS Config sends notifications about configuration changes. | +| config\_snapshot\_delivery\_properties\_delivery\_frequency | The frequency with which AWS Config delivers configuration snapshots. | +| region | The region of the delivery channel. | + +#### Relationships + +- AWS Config Delivery Channels are a resource under the AWS Account. + + ``` + (AWSAccount)-[RESOURCE]->(AWSConfigDeliveryChannel) + ``` + +### AWSConfigRule + +Representation of an AWS [Config Rule](https://docs.aws.amazon.com/config/latest/APIReference/API_DeliveryChannel.html) + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The ARN of the config rule. | +| name | The name of the delivery channel. | +| description | The description that you provide for the AWS Config rule. | +| arn | The ARN of the config rule. | +| rule\_id | The ID of the AWS Config rule. | +| scope\_compliance\_resource\_types | The resource types of only those AWS resources that you want to trigger an evaluation for the rule. You can only specify one type if you also specify a resource ID for ComplianceResourceId. | +| scope\_tag\_key | The tag key that is applied to only those AWS resources that you want to trigger an evaluation for the rule. | +| scope\_tag\_value | The tag value applied to only those AWS resources that you want to trigger an evaluation for the rule. If you specify a value for TagValue, you must also specify a value for TagKey. | +| scope\_tag\_compliance\_resource\_id | The resource types of only those AWS resources that you want to trigger an evaluation for the rule. You can only specify one type if you also specify a resource ID for ComplianceResourceId. | +| source\_owner | Indicates whether AWS or the customer owns and manages the AWS Config rule. | +| source\_identifier | For AWS Config managed rules, a predefined identifier from a list. For example, IAM\_PASSWORD\_POLICY is a managed rule. | +| source\_details | Provides the source and type of the event that causes AWS Config to evaluate your AWS resources. | +| input\_parameters | A string, in JSON format, that is passed to the AWS Config rule Lambda function. | +| maximum\_execution\_frequency | The maximum frequency with which AWS Config runs evaluations for a rule. | +| created\_by | Service principal name of the service that created the rule. | +| region | The region of the delivery channel. | + +#### Relationships + +- AWS Config Rules are a resource under the AWS Account. + + ``` + (AWSAccount)-[RESOURCE]->(AWSConfigRule) + ``` + +### LaunchConfiguration + +Representation of an AWS [Launch Configuration](https://docs.aws.amazon.com/autoscaling/ec2/APIReference/API_LaunchConfiguration.html) + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The ARN of the launch configuration. | +| name | The name of the launch configuration. | +| arn | The ARN of the launch configuration. | +| created\_time| The creation date and time for the launch configuration. | +| image\_id | The ID of the Amazon Machine Image (AMI) to use to launch your EC2 instances. | +| key\_name | The name of the key pair. | +| security\_groups | A list that contains the security groups to assign to the instances in the Auto Scaling group. | +| instance\_type | The instance type for the instances. | +| kernel\_id | The ID of the kernel associated with the AMI. | +| ramdisk\_id | The ID of the RAM disk associated with the AMI. | +| instance\_monitoring\_enabled | If true, detailed monitoring is enabled. Otherwise, basic monitoring is enabled. | +| spot\_price | The maximum hourly price to be paid for any Spot Instance launched to fulfill the request. | +| iam\_instance\_profile | The name or the Amazon Resource Name (ARN) of the instance profile associated with the IAM role for the instance. | +| ebs\_optimized | Specifies whether the launch configuration is optimized for EBS I/O (true) or not (false). | +| associate\_public\_ip\_address | For Auto Scaling groups that are running in a VPC, specifies whether to assign a public IP address to the group's instances. | +| placement\_tenancy | The tenancy of the instance, either default or dedicated. An instance with dedicated tenancy runs on isolated, single-tenant hardware and can only be launched into a VPC. | +| region | The region of the launch configuration. | + +#### Relationships + +- Launch Configurations are a resource under the AWS Account. + + ``` + (AWSAccount)-[RESOURCE]->(LaunchConfiguration) + ``` + +### LaunchTemplate + +Representation of an AWS [Launch Template](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_LaunchTemplate.html) + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The ID of the launch template. | +| name | The name of the launch template. | +| create\_time | The time launch template was created. | +| created\_by | The principal that created the launch template. | +| default\_version\_number | The version number of the default version of the launch template. | +| latest\_version\_number | The version number of the latest version of the launch template. | +| region | The region of the launch template. | + +#### Relationships + +- Launch Templates are a resource under the AWS Account. + + ``` + (AWSAccount)-[RESOURCE]->(LaunchTemplate) + ``` +- Launch templates have Launch Template Versions + + ``` + (LaunchTemplate)-[VERSION]->(LaunchTemplateVersion) + ``` + +### LaunchTemplateVersion + +Representation of an AWS [Launch Template Version](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_LaunchTemplateVersion.html) + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The ID of the launch template version (ID-version). | +| name | The name of the launch template. | +| create\_time | The time the version was created. | +| created\_by | The principal that created the version. | +| default\_version | Indicates whether the version is the default version. | +| version\_number | The version number. | +| version\_description | The description of the version. | +| kernel\_id | The ID of the kernel, if applicable. | +| ebs\_optimized | Indicates whether the instance is optimized for Amazon EBS I/O. | +| iam\_instance\_profile\_arn | The Amazon Resource Name (ARN) of the instance profile. | +| iam\_instance\_profile\_name | The name of the instance profile. | +| image\_id | The ID of the AMI that was used to launch the instance. | +| instance\_type | The instance type. | +| key\_name | The name of the key pair. | +| monitoring\_enabled | Indicates whether detailed monitoring is enabled. Otherwise, basic monitoring is enabled. | +| ramdisk\_id | The ID of the RAM disk, if applicable. | +| disable\_api\_termination | If set to true, indicates that the instance cannot be terminated using the Amazon EC2 console, command line tool, or API. | +| instance\_initiated\_shutdown\_behavior | Indicates whether an instance stops or terminates when you initiate shutdown from the instance (using the operating system command for system shutdown). | +| security\_group\_ids | The security group IDs. | +| security\_groups | The security group names. | +| region | The region of the launch template. | + +#### Relationships + +- Launch Template Versions are a resource under the AWS Account. + + ``` + (AWSAccount)-[RESOURCE]->(LaunchTemplateVersion) + ``` + +### ElasticIPAddress + +Representation of an AWS EC2 [Elastic IP address](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_Address.html) + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The Elastic IP address | +| instance\_id | The ID of the instance that the address is associated with (if any). | +| public\_ip | The Elastic IP address. | +| allocation\_id | The ID representing the allocation of the address for use with EC2-VPC. | +| association\_id | The ID representing the association of the address with an instance in a VPC. | +| domain | Indicates whether this Elastic IP address is for use with instances in EC2-Classic (standard) or instances in a VPC (vpc). | +| network\_interface\_id | The ID of the network interface. | +| private\_ip\_address | The private IP address associated with the Elastic IP address. | +| public\_ipv4\_pool | The ID of an address pool. | +| network\_border\_group | The name of the unique set of Availability Zones, Local Zones, or Wavelength Zones from which AWS advertises IP addresses. | +| customer\_owned\_ip | The customer-owned IP address. | +| customer\_owned\_ipv4\_pool | The ID of the customer-owned address pool. | +| carrier\_ip | The carrier IP address associated. This option is only available for network interfaces which reside in a subnet in a Wavelength Zone (for example an EC2 instance). | +| region | The region of the IP. | + +#### Relationships + +- Elastic IPs are a resource under the AWS Account. + + ``` + (AWSAccount)-[RESOURCE]->(ElasticIPAddress) + ``` + +- Elastic IPs can be attached to EC2 instances + + ``` + (EC2Instance)-[ELASTIC_IP_ADDRESS]->(ElasticIPAddress) + ``` + +- Elastic IPs can be attached to NetworkInterfaces + + ``` + (NetworkInterface)-[ELASTIC_IP_ADDRESS]->(ElasticIPAddress) + ``` + +### ECSCluster + +Representation of an AWS ECS [Cluster](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_Cluster.html) + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The ARN of the cluster | +| region | The region of the cluster. | +| name | A user-generated string that you use to identify your cluster. | +| arn | The ARN of the cluster | +| ecc\_kms\_key\_id | An AWS Key Management Service key ID to encrypt the data between the local client and the container. | +| ecc\_logging | The log setting to use for redirecting logs for your execute command results. | +| ecc\_log\_configuration\_cloud\_watch\_log\_group\_name | The name of the CloudWatch log group to send logs to. | +| ecc\_log\_configuration\_cloud\_watch\_encryption\_enabled | Determines whether to enable encryption on the CloudWatch logs. | +| ecc\_log\_configuration\_s3\_bucket\_name | The name of the S3 bucket to send logs to. | +| ecc\_log\_configuration\_s3\_encryption\_enabled | Determines whether to use encryption on the S3 logs. | +| ecc\_log\_configuration\_s3\_key\_prefix | An optional folder in the S3 bucket to place logs in. | +| status | The status of the cluster | +| settings\_container\_insights | If enabled is specified, CloudWatch Container Insights will be enabled for the cluster, otherwise it will be disabled unless the containerInsights account setting is enabled. | +| capacity\_providers | The capacity providers associated with the cluster. | +| attachments\_status | The status of the capacity providers associated with the cluster. | + +#### Relationships + +- ECSClusters are a resource under the AWS Account. + + ``` + (AWSAccount)-[RESOURCE]->(ECSCluster) + ``` + +### ECSContainerInstance + +Representation of an AWS ECS [Container Instance](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ContainerInstance.html) + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The ARN of the container instance | +| region | The region of the container instance. | +| ec2\_instance\_id | The ID of the container instance. For Amazon EC2 instances, this value is the Amazon EC2 instance ID. For external instances, this value is the AWS Systems Manager managed instance ID. | +| arn | The ARN of the container instance | +| capacity\_provider\_name | The capacity provider that's associated with the container instance. | +| version | The version counter for the container instance. | +| version\_info\_agent\_version | The version number of the Amazon ECS container agent. | +| version\_info\_agent\_hash | The Git commit hash for the Amazon ECS container agent build on the amazon-ecs-agent GitHub repository. | +| version\_info\_agent\_docker\_version | The Docker version that's running on the container instance. | +| status | The status of the container instance. | +| status\_reason | The reason that the container instance reached its current status. | +| agent\_connected | This parameter returns true if the agent is connected to Amazon ECS. Registered instances with an agent that may be unhealthy or stopped return false. | +| agent\_update\_status | The status of the most recent agent update. If an update wasn't ever requested, this value is NULL. | +| registered\_at | The Unix timestamp for the time when the container instance was registered. | + +#### Relationships + +- An ECSCluster has ECSContainerInstances + + ``` + (ECSCluster)-[HAS_CONTAINER_INSTANCE]->(ECSContainerInstance) + ``` + +- ECSContainerInstances have ECSTasks + + ``` + (ECSContainerInstance)-[HAS_TASK]->(ECSTask) + ``` + +### ECSService + +Representation of an AWS ECS [Service](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_Service.html) + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The ARN of the service | +| region | The region of the service. | +| name | The name of your service. | +| arn | The ARN of the service | +| cluster_arn | The Amazon Resource Name (ARN) of the cluster that hosts the service. | +| status | The status of the service. | +| desired\_count | The desired number of instantiations of the task definition to keep running on the service. | +| running\_count | The number of tasks in the cluster that are in the RUNNING state. | +| pending\_count | The number of tasks in the cluster that are in the PENDING state. | +| launch\_type | The launch type the service is using. | +| platform\_version | The platform version to run your service on. A platform version is only specified for tasks that are hosted on AWS Fargate. | +| platform\_family | The operating system that your tasks in the service run on. A platform family is specified only for tasks using the Fargate launch type. | +| task\_definition | The task definition to use for tasks in the service. | +| deployment\_config\_circuit\_breaker\_enable | Determines whether to enable the deployment circuit breaker logic for the service. | +| deployment\_config\_circuit\_breaker\_rollback | Determines whether to enable Amazon ECS to roll back the service if a service deployment fails. | +| deployment\_config\_maximum\_percent | If a service is using the rolling update (ECS) deployment type, the maximum percent parameter represents an upper limit on the number of tasks in a service that are allowed in the RUNNING or PENDING state during a deployment, as a percentage of the desired number of tasks (rounded down to the nearest integer), and while any container instances are in the DRAINING state if the service contains tasks using the EC2 launch type. | +| deployment\_config\_minimum\_healthy\_percent | If a service is using the rolling update (ECS) deployment type, the minimum healthy percent represents a lower limit on the number of tasks in a service that must remain in the RUNNING state during a deployment, as a percentage of the desired number of tasks (rounded up to the nearest integer), and while any container instances are in the DRAINING state if the service contains tasks using the EC2 launch type. | +| role\_arn | The ARN of the IAM role that's associated with the service. | +| created\_at | The Unix timestamp for the time when the service was created. | +| health\_check\_grace\_period\_seconds | The period of time, in seconds, that the Amazon ECS service scheduler ignores unhealthy Elastic Load Balancing target health checks after a task has first started. | +| created\_by | The principal that created the service. | +| enable\_ecs\_managed\_tags | Determines whether to enable Amazon ECS managed tags for the tasks in the service. | +| propagate\_tags | Determines whether to propagate the tags from the task definition or the service to the task. | +| enable\_execute\_command | Determines whether the execute command functionality is enabled for the service. | + +#### Relationships + +- An ECSCluster has ECSService + + ``` + (ECSCluster)-[HAS_SERVICE]->(ECSService) + ``` + +- An ECSCluster has ECSContainerInstances + + ``` + (ECSCluster)-[HAS_CONTAINER_INSTANCE]->(ECSContainerInstance) + ``` + +### ECSTaskDefinition + +Representation of an AWS ECS [Task Definition](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_TaskDefinition.html) + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The ARN of the task definition | +| region | The region of the task definition. | +| family | The name of a family that this task definition is registered to. | +| task\_role\_arn | The short name or full Amazon Resource Name (ARN) of the AWS Identity and Access Management role that grants containers in the task permission to call AWS APIs on your behalf. | +| execution\_role\_arn | The Amazon Resource Name (ARN) of the task execution role that grants the Amazon ECS container agent permission to make AWS API calls on your behalf. | +| network\_mode | The Docker networking mode to use for the containers in the task. The valid values are none, bridge, awsvpc, and host. If no network mode is specified, the default is bridge. | +| revision | The revision of the task in a particular family. | +| status | The status of the task definition. | +| compatibilities | The task launch types the task definition validated against during task definition registration. | +| runtime\_platform\_cpu\_architecture | The CPU architecture. | +| runtime\_platform\_operating\_system\_family | The operating system. | +| requires\_compatibilities | The task launch types the task definition was validated against. | +| cpu | The number of cpu units used by the task. | +| memory | The amount (in MiB) of memory used by the task. | +| pid\_mode | The process namespace to use for the containers in the task. | +| ipc\_mode | The IPC resource namespace to use for the containers in the task. | +| proxy\_configuration\_type | The proxy type. | +| proxy\_configuration\_container\_name | The name of the container that will serve as the App Mesh proxy. | +| registered\_at | The Unix timestamp for the time when the task definition was registered. | +| deregistered\_at | The Unix timestamp for the time when the task definition was deregistered. | +| registered\_by | The principal that registered the task definition. | +| ephemeral\_storage\_size\_in\_gib | The total amount, in GiB, of ephemeral storage to set for the task. | + +#### Relationships + +- ECSTaskDefinition are a resource under the AWS Account. + + ``` + (AWSAccount)-[RESOURCE]->(ECSTaskDefinition) + ``` + +- An ECSTask has an ECSTaskDefinition. + + ``` + (ECSTask)-[HAS_TASK_DEFINITION]->(ECSTaskDefinition) + ``` + +### ECSContainerDefinition + +Representation of an AWS ECS [Container Definition](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ContainerDefinition.html) + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The ARN of the task definition, plus the container definition name | +| region | The region of the container definition. | +| name | The name of a container. | +| image | The image used to start a container. This string is passed directly to the Docker daemon. | +| cpu | The number of cpu units reserved for the container. | +| memory | The amount (in MiB) of memory to present to the container. | +| memory\_reservation | The soft limit (in MiB) of memory to reserve for the container. | +| links | The links parameter allows containers to communicate with each other without the need for port mappings. | +| essential | If the essential parameter of a container is marked as true, and that container fails or stops for any reason, all other containers that are part of the task are stopped. | +| entry\_point | The entry point that's passed to the container. | +| command | The command that's passed to the container. | +| start\_timeout | Time duration (in seconds) to wait before giving up on resolving dependencies for a container. | +| stop\_timeout | Time duration (in seconds) to wait before the container is forcefully killed if it doesn't exit normally on its own. | +| hostname | The hostname to use for your container. | +| user | The user to use inside the container. | +| working\_directory | The working directory to run commands inside the container in. | +| disable\_networking | When this parameter is true, networking is disabled within the container. | +| privileged | When this parameter is true, the container is given elevated privileges on the host container instance (similar to the root user). | +| readonly\_root\_filesystem | When this parameter is true, the container is given read-only access to its root file system. | +| dns\_servers | A list of DNS servers that are presented to the container. | +| dns\_search\_domains | A list of DNS search domains that are presented to the container. | +| docker\_security\_options | A list of strings to provide custom labels for SELinux and AppArmor multi-level security systems. This field isn't valid for containers in tasks using the Fargate launch type. | +| interactive | When this parameter is true, you can deploy containerized applications that require stdin or a tty to be allocated. | +| pseudo\_terminal | When this parameter is true, a TTY is allocated. | + +#### Relationships + +- ECSTaskDefinitions have ECSContainerDefinitions + + ``` + (ECSTaskDefinition)-[HAS_CONTAINER_DEFINITION]->(ECSContainerDefinition) + ``` + +### ECSTask + +Representation of an AWS ECS [Task](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_Task.html) + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The ARN of the task | +| region | The region of the task. | +| arn | The arn of the task. | +| availability\_zone | The Availability Zone for the task. | +| capacity\_provider\_name | The capacity provider that's associated with the task. | +| cluster\_arn | The ARN of the cluster that hosts the task. | +| connectivity | The connectivity status of a task. | +| connectivity\_at | The Unix timestamp for the time when the task last went into CONNECTED status. | +| container\_instance\_arn | The ARN of the container instances that host the task. | +| cpu | The number of CPU units used by the task as expressed in a task definition. | +| created\_at | The Unix timestamp for the time when the task was created. More specifically, it's for the time when the task entered the PENDING state. | +| desired\_status | The desired status of the task. | +| enable\_execute\_command | Determines whether execute command functionality is enabled for this task. | +| execution\_stopped\_at | The Unix timestamp for the time when the task execution stopped. | +| group | The name of the task group that's associated with the task. | +| health\_status | The health status for the task. | +| last\_status | The last known status for the task. | +| launch\_type | The infrastructure where your task runs on. | +| memory | The amount of memory (in MiB) that the task uses as expressed in a task definition. | +| platform\_version | The platform version where your task runs on. | +| platform\_family | The operating system that your tasks are running on. | +| pull\_started\_at | The Unix timestamp for the time when the container image pull began. | +| pull\_stopped\_at | The Unix timestamp for the time when the container image pull completed. | +| started\_at | The Unix timestamp for the time when the task started. More specifically, it's for the time when the task transitioned from the PENDING state to the RUNNING state. | +| started\_by | The tag specified when a task is started. If an Amazon ECS service started the task, the startedBy parameter contains the deployment ID of that service. | +| stop\_code | The stop code indicating why a task was stopped. | +| stopped\_at | The Unix timestamp for the time when the task was stopped. More specifically, it's for the time when the task transitioned from the RUNNING state to the STOPPED state. | +| stopped\_reason | The reason that the task was stopped. | +| stopping\_at | The Unix timestamp for the time when the task stops. More specifically, it's for the time when the task transitions from the RUNNING state to STOPPED. | +| task\_definition\_arn | The ARN of the task definition that creates the task. | +| version | The version counter for the task. | +| ephemeral\_storage\_size\_in\_gib | The total amount, in GiB, of ephemeral storage to set for the task. | + +#### Relationships + +- ECSClusters have ECSTasks + + ``` + (ECSCluster)-[HAS_TASK]->(ECSTask) + ``` + +- ECSContainerInstances have ECSTasks + + ``` + (ECSContainerInstance)-[HAS_TASK]->(ECSTask) + ``` + +- ECSTasks have ECSTaskDefinitions + + ``` + (ECSTask)-[HAS_TASK_DEFINITION]->(ECSTaskDefinition) + ``` + +### ECSContainer + +Representation of an AWS ECS [Container](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_Container.html) + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The ARN of the container | +| region | The region of the container. | +| arn | The arn of the container. | +| task\_arn | The ARN of the task. | +| name | The name of the container. | +| image | The image used for the container. | +| image\_digest | The container image manifest digest. | +| runtime\_id | The ID of the Docker container. | +| last\_status | The last known status of the container. | +| exit\_code | The exit code returned from the container. | +| reason | A short (255 max characters) human-readable string to provide additional details about a running or stopped container. | +| health\_status | The health status of the container. | +| cpu | The number of CPU units set for the container. | +| memory | The hard limit (in MiB) of memory set for the container. | +| memory\_reservation | The soft limit (in MiB) of memory set for the container. | +| gpu\_ids | The IDs of each GPU assigned to the container. | + +#### Relationships + +- ECSTasks have ECSContainers + + ``` + (ECSTask)-[HAS_CONTAINER]->(ECSContainer) + ``` + +### SSMInstanceInformation + +Representation of an AWS SSM [InstanceInformation](https://docs.aws.amazon.com/systems-manager/latest/APIReference/API_InstanceInformation.html) + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The ARN of the instance information | +| region | The region of the instance information. | +| instance\_id | The managed node ID. | +| ping\_status | Connection status of SSM Agent. | +| last\_ping\_date\_time | The date and time when the agent last pinged the Systems Manager service. | +| agent\_version | The version of SSM Agent running on your Linux managed node. | +| is\_latest\_version | Indicates whether the latest version of SSM Agent is running on your Linux managed node. This field doesn't indicate whether or not the latest version is installed on Windows managed nodes, because some older versions of Windows Server use the EC2Config service to process Systems Manager requests. | +| platform\_type | The operating system platform type. | +| platform\_name | The name of the operating system platform running on your managed node. | +| platform\_version | The version of the OS platform running on your managed node. | +| activation\_id | The activation ID created by AWS Systems Manager when the server or virtual machine (VM) was registered. | +| iam\_role | The AWS Identity and Access Management (IAM) role assigned to the on-premises Systems Manager managed node. This call doesn't return the IAM role for Amazon Elastic Compute Cloud (Amazon EC2) instances. | +| registration\_date | The date the server or VM was registered with AWS as a managed node. | +| resource\_type | The type of instance. Instances are either EC2 instances or managed instances. | +| name | The name assigned to an on-premises server, edge device, or virtual machine (VM) when it is activated as a Systems Manager managed node. The name is specified as the DefaultInstanceName property using the CreateActivation command. | +| ip\_address | The IP address of the managed node. | +| computer\_name | The fully qualified host name of the managed node. | +| association\_status | The status of the association. | +| last\_association\_execution\_date | The date the association was last run. | +| last\_successful\_association\_execution\_date | The last date the association was successfully run. | +| source\_id | The ID of the source resource. For AWS IoT Greengrass devices, SourceId is the Thing name. | +| source\_type | The type of the source resource. For AWS IoT Greengrass devices, SourceType is AWS::IoT::Thing. | + +#### Relationships + +- SSMInstanceInformation is a resource under the AWS Account. + + ``` + (AWSAccount)-[RESOURCE]->(SSMInstanceInformation) + ``` + +- SSMInstanceInformation is a resource of an EC2Instance + + ``` + (EC2Instance)-[HAS_INFORMATION]->(SSMInstanceInformation) + ``` + +### SSMInstancePatch + +Representation of an AWS SSM [PatchComplianceData](https://docs.aws.amazon.com/systems-manager/latest/APIReference/API_PatchComplianceData.html) + +| Field | Description | +|-------|-------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The ARN of the instance patch | +| region | The region of the instance patch. | +| instance\_id | The managed node ID. | +| title | The title of the patch. | +| kb\_id | The operating system-specific ID of the patch. | +| classification | The classification of the patch, such as SecurityUpdates, Updates, and CriticalUpdates. | +| severity | The severity of the patch such as Critical, Important, and Moderate. | +| state | The state of the patch on the managed node, such as INSTALLED or FAILED. | +| installed\_time | The date/time the patch was installed on the managed node. Not all operating systems provide this level of information. | +| cve\_ids | The IDs of one or more Common Vulnerabilities and Exposure (CVE) issues that are resolved by the patch. | + +#### Relationships + +- SSMInstancePatch is a resource under the AWS Account. + + ``` + (AWSAccount)-[RESOURCE]->(SSMInstancePatch) + ``` + +- EC2Instances have SSMInstancePatches + + ``` + (EC2Instance)-[HAS_INFORMATION]->(SSMInstancePatch) + ``` diff --git a/_sources/modules/azure/config.md.txt b/_sources/modules/azure/config.md.txt new file mode 100644 index 0000000000..92d6f808d9 --- /dev/null +++ b/_sources/modules/azure/config.md.txt @@ -0,0 +1,18 @@ +## Azure Configuration + +.. _azure_config: + +Follow these steps to analyze Microsoft Azure assets with Cartography: + +1. Set up an Azure identity for Cartography to use, and ensure that this identity has the built-in Azure [Reader role](https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#reader) attached: + * Authenticate: `$ az login` + * Create a Service Principal: `$ az ad sp create-for-rbac --name cartography --role Reader` + * Note the values of the `tenant`, `appId`, and `password` fields +1. Populate environment variables with the values generated in the previous step (e.g., `AZURE_TENANT_ID`, `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET`) +1. Call the `cartography` CLI with: + ```bash + --azure-sp-auth --azure-sync-all-subscriptions \ + --azure-tenant-id ${AZURE_TENANT_ID} \ + --azure-client-id ${AZURE_CLIENT_ID} \ + --azure-client-secret-env-var AZURE_CLIENT_SECRET + ``` diff --git a/_sources/modules/azure/index.rst.txt b/_sources/modules/azure/index.rst.txt new file mode 100644 index 0000000000..3b82e79cd6 --- /dev/null +++ b/_sources/modules/azure/index.rst.txt @@ -0,0 +1,15 @@ +Microsoft Azure +############### + +The azure module has the following coverage: + +* CosmosDB +* SQL +* Storage +* Virtual Machine + +.. toctree:: + :hidden: + :glob: + + * diff --git a/_sources/modules/azure/schema.md.txt b/_sources/modules/azure/schema.md.txt new file mode 100644 index 0000000000..f18fae648f --- /dev/null +++ b/_sources/modules/azure/schema.md.txt @@ -0,0 +1,1173 @@ +## Azure Schema + +.. _azure_schema: + +### AzureTenant + +Representation of an [Azure Tenant](https://docs.microsoft.com/en-us/rest/api/resources/Tenants/List). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The Azure Tenant ID number| + +#### Relationships + +- Azure Principal is part of the Azure Account. + + ``` + (AzureTenant)-[RESOURCE]->(AzurePrincipal) + ``` + +### AzurePrincipal + +Representation of an [Azure Principal](https://docs.microsoft.com/en-us/graph/api/resources/user?view=graph-rest-1.0).. + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**email**| Email of the Azure Principal| + +#### Relationships + +- Azure Principal is part of the Azure Account. + + ``` + (AzurePrincipal)-[RESOURCE]->(AzureTenant) + ``` + +### AzureSubscription + +Representation of an [Azure Subscription](https://docs.microsoft.com/en-us/rest/api/resources/subscriptions).. + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The Azure Subscription ID number| +|name | The friendly name that identifies the subscription| +|path | The full ID for the Subscription| +|state| Can be one of ``Enabled \| Disabled \| Deleted \| PastDue \| Warned``| + +#### Relationships + +- Azure Tenant contains one or more Subscriptions. + + ``` + (AzureTenant)-[RESOURCE]->(AzureSubscription) + ``` + +### VirtualMachine + +Representation of an [Azure Virtual Machine](https://docs.microsoft.com/en-us/rest/api/compute/virtualmachines). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The Azure Virtual Machine ID number| +|type | The type of the resource| +|location | The location where Virtual Machine is created| +|resourcegroup | The Resource Group where Virtual Machine is created| +|name | The friendly name that identifies the Virtual Machine| +|plan | The plan associated with the Virtual Machine| +|size | The size of the Virtual Machine| +|license\_type | The type of license| +|computer\_name | The computer name| +|identity\_type | The type of identity used for the virtual machine| +|zones | The Virtual Machine zones| +|ultra\_ssd\_enabled | Enables or disables a capability on the virtual machine or virtual machine scale set.| +|priority | Specifies the priority for the virtual machine| +|eviction\_policy | Specifies the eviction policy for the Virtual Machine| + +#### Relationships + +- Azure Subscription contains one or more Virtual Machines. + + ``` + (AzureSubscription)-[RESOURCE]->(VirtualMachine) + ``` + +### AzureDataDisk + +Representation of an [Azure Data Disk](https://docs.microsoft.com/en-us/rest/api/compute/virtualmachines/get#datadisk). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The Azure Data Disk ID number| +|lun | Specifies the logical unit number of the data disk| +|name | The data disk name| +|vhd | The virtual hard disk associated with data disk| +|image | The source user image virtual hard disk| +|size | The size of the disk in GB| +|caching | Specifies the caching requirement| +|createoption | Specifies how the disk should be created| +|write\_accelerator\_enabled | Specifies whether writeAccelerator should be enabled or disabled on the data disk| +|managed\_disk\_storage\_type | The data disk storage type| + +#### Relationships + +- Azure Virtual Machines are attached to Data Disks. + + ``` + (VirtualMachine)-[ATTACHED_TO]->(AzureDataDisk) + ``` + +### AzureDisk + +Representation of an [Azure Disk](https://docs.microsoft.com/en-us/rest/api/compute/disks). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The Azure Disk ID number| +|type | The type of the resource| +|location | The location where Disk is created| +|resourcegroup | The Resource Group where Disk is created| +|name | The friendly name that identifies the Disk| +|createoption | Specifies how the disk should be created| +|disksizegb | The size of the disk in GB| +|encryption | Specifies whether the disk has encryption enabled | +|maxshares | Specifies how many machines can share the disk| +|ostype | The operating system type of the disk| +|tier | Performance Tier associated with the disk| +|sku | The disk sku name| +|zones | The logical zone list for disk| + +#### Relationships + +- Azure Subscription contains one or more Disks. + + ``` + (AzureSubscription)-[RESOURCE]->(AzureDisk) + ``` + +### AzureSnapshot + +Representation of an [Azure Snapshot](https://docs.microsoft.com/en-us/rest/api/compute/snapshots). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The Azure Snapshot ID number| +|type | The type of the resource| +|location | The location where snapshot is created| +|resourcegroup | The Resource Group where snapshot is created| +|name | The friendly name that identifies the snapshot| +|createoption | Specifies how the disk should be created| +|disksizegb | The size of the snapshot in GB| +|encryption | Specifies whether the snapshot has encryption enabled | +|incremental | Indicates whether a snapshot is incremental or not | +|network\_access\_policy | Policy for accessing the snapshot via network| +|ostype | The operating system type of the snapshot| +|tier | Performance Tier associated with the snapshot| +|sku | The snapshot sku name| +|zones | The logical zone list for snapshot| + +#### Relationships + +- Azure Subscription contains one or more Snapshots. + + ``` + (AzureSubscription)-[RESOURCE]->(AzureSnapshot) + ``` + +### AzureSQLServer + +Representation of an [AzureSQLServer](https://docs.microsoft.com/en-us/rest/api/sql/servers). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The resource ID| +|location | The location where the resource is created| +|resourcegroup | The Resource Group where SQL Server is created| +|name | The friendly name that identifies the SQL server| +|kind | Specifies the kind of SQL server| +|state | The state of the server| +|version | The version of the server | + +#### Relationships + +- Azure Subscription contains one or more SQL Servers. + + ``` + (AzureSubscription)-[RESOURCE]->(AzureSQLServer) + ``` +- Azure SQL Server can be used by one or more Azure Server DNS Aliases. + + ``` + (AzureSQLServer)-[USED_BY]->(AzureServerDNSAlias) + ``` +- Azure SQL Server can be administered by one or more Azure Server AD Administrators. + + ``` + (AzureSQLServer)-[ADMINISTERED_BY]->(AzureServerADAdministrator) + ``` +- Azure SQL Server has one or more Azure Recoverable Database. + + ``` + (AzureSQLServer)-[RESOURCE]->(AzureRecoverableDatabase) + ``` +- Azure SQL Server has one or more Azure Restorable Dropped Database. + + ``` + (AzureSQLServer)-[RESOURCE]->(AzureRestorableDroppedDatabase) + ``` +- Azure SQL Server has one or more Azure Failover Group. + + ``` + (AzureSQLServer)-[RESOURCE]->(AzureFailoverGroup) + ``` +- Azure SQL Server has one or more Azure Elastic Pool. + + ``` + (AzureSQLServer)-[RESOURCE]->(AzureElasticPool) + ``` +- Azure SQL Server has one or more Azure SQL Database. + + ``` + (AzureSQLServer)-[RESOURCE]->(AzureSQLDatabase) + ``` + +### AzureServerDNSAlias + +Representation of an [AzureServerDNSAlias](https://docs.microsoft.com/en-us/rest/api/sql/serverdnsaliases). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The resource ID| +|name | The name of the server DNS alias| +|dnsrecord | The fully qualified DNS record for alias.| + +#### Relationships + +- Azure SQL Server can be used by one or more Azure Server DNS Aliases. + + ``` + (AzureSQLServer)-[USED_BY]->(AzureServerDNSAlias) + ``` + +### AzureServerADAdministrator + +Representation of an [AzureServerADAdministrator](https://docs.microsoft.com/en-us/rest/api/sql/serverazureadadministrators). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The resource ID| +|name | The name of the resource.| +|administratortype | The type of the server administrator.| +|login | The login name of the server administrator.| + +#### Relationships + +- Azure SQL Server can be administered by one or more Azure Server AD Administrators. + + ``` + (AzureSQLServer)-[ADMINISTERED_BY]->(AzureServerADAdministrator) + ``` + +### AzureRecoverableDatabase + +Representation of an [AzureRecoverableDatabase](https://docs.microsoft.com/en-us/rest/api/sql/recoverabledatabases). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The resource ID| +|name | The name of the resource.| +|edition | The edition of the database.| +|servicelevelobjective | The service level objective name of the database.| +|lastbackupdate | The last available backup date of the database (ISO8601 format).| + +#### Relationships + +- Azure SQL Server has one or more Azure Recoverable Database. + + ``` + (AzureSQLServer)-[RESOURCE]->(AzureRecoverableDatabase) + ``` + +### AzureRestorableDroppedDatabase + +Representation of an [AzureRestorableDroppedDatabase](https://docs.microsoft.com/en-us/rest/api/sql/restorabledroppeddatabases). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The resource ID| +|name | The name of the resource.| +|location | The geo-location where the resource lives.| +|databasename | The name of the database.| +|creationdate | The creation date of the database (ISO8601 format).| +|deletiondate | The deletion date of the database (ISO8601 format).| +|restoredate | The earliest restore date of the database (ISO8601 format).| +|edition | The edition of the database.| +|servicelevelobjective | The service level objective name of the database.| +|maxsizebytes | The max size in bytes of the database.| + +#### Relationships + +- Azure SQL Server has one or more Azure Restorable Dropped Database. + + ``` + (AzureSQLServer)-[RESOURCE]->(AzureRestorableDroppedDatabase) + ``` + +### AzureFailoverGroup + +Representation of an [AzureFailoverGroup](https://docs.microsoft.com/en-us/rest/api/sql/failovergroups). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The resource ID| +|name | The name of the resource.| +|location | The geo-location where the resource lives.| +|replicationrole | Local replication role of the failover group instance.| +|replicationstate | Replication state of the failover group instance.| + +#### Relationships + +- Azure SQL Server has one or more Azure Failover Group. + + ``` + (AzureSQLServer)-[RESOURCE]->(AzureFailoverGroup) + ``` + +### AzureElasticPool + +Representation of an [AzureElasticPool](https://docs.microsoft.com/en-us/rest/api/sql/elasticpools). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The resource ID| +|name | The name of the resource.| +|location | The location of the resource.| +|kind | The kind of elastic pool.| +|creationdate | The creation date of the elastic pool (ISO8601 format).| +|state | The state of the elastic pool.| +|maxsizebytes | The storage limit for the database elastic pool in bytes.| +|licensetype | The license type to apply for this elastic pool. | +|zoneredundant | Specifies whether or not this elastic pool is zone redundant, which means the replicas of this elastic pool will be spread across multiple availability zones.| + +#### Relationships + +- Azure SQL Server has one or more Azure Elastic Pool. + + ``` + (AzureSQLServer)-[RESOURCE]->(AzureElasticPool) + ``` + +### AzureSQLDatabase + +Representation of an [AzureSQLDatabase](https://docs.microsoft.com/en-us/rest/api/sql/databases). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The resource ID| +|name | The name of the resource.| +|location | The location of the resource.| +|kind | The kind of database.| +|creationdate | The creation date of the database (ISO8601 format).| +|databaseid | The ID of the database.| +|maxsizebytes | The max size of the database expressed in bytes.| +|licensetype | The license type to apply for this database.| +|secondarylocation | The default secondary region for this database.| +|elasticpoolid | The resource identifier of the elastic pool containing this database.| +|collation | The collation of the database.| +|failovergroupid | Failover Group resource identifier that this database belongs to.| +|zoneredundant | Whether or not this database is zone redundant, which means the replicas of this database will be spread across multiple availability zones.| +|restorabledroppeddbid | The resource identifier of the restorable dropped database associated with create operation of this database.| +|recoverabledbid | The resource identifier of the recoverable database associated with create operation of this database.| + +#### Relationships + +- Azure SQL Server has one or more Azure SQL Database. + + ``` + (AzureSQLServer)-[RESOURCE]->(AzureSQLDatabase) + ``` +- Azure SQL Database contains one or more Azure Replication Links. + + ``` + (AzureSQLDatabase)-[CONTAINS]->(AzureReplicationLink) + ``` +- Azure SQL Database contains a Database Threat Detection Policy. + + ``` + (AzureSQLDatabase)-[CONTAINS]->(AzureDatabaseThreatDetectionPolicy) + ``` +- Azure SQL Database contains one or more Restore Points. + + ``` + (AzureSQLDatabase)-[CONTAINS]->(AzureRestorePoint) + ``` +- Azure SQL Database contains Transparent Data Encryption. + + ``` + (AzureSQLDatabase)-[CONTAINS]->(AzureTransparentDataEncryption) + ``` + +### AzureReplicationLink + +Representation of an [AzureReplicationLink](https://docs.microsoft.com/en-us/rest/api/sql/replicationlinks). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The resource ID| +|name | The name of the resource.| +|location | Location of the server that contains this firewall rule.| +|partnerdatabase | The name of the partner database.| +|partnerlocation | The Azure Region of the partner database.| +|partnerrole | The role of the database in the replication link.| +|partnerserver | The name of the server hosting the partner database.| +|mode | Replication mode of this replication link.| +|state | The replication state for the replication link.| +|percentcomplete | The percentage of seeding complete for the replication link.| +|role | The role of the database in the replication link.| +|starttime | The start time for the replication link.| +|terminationallowed | Legacy value indicating whether termination is allowed.| + +#### Relationships + +- Azure SQL Database contains one or more Azure Replication Links. + + ``` + (AzureSQLDatabase)-[CONTAINS]->(AzureReplicationLink) + ``` + +### AzureDatabaseThreatDetectionPolicy + +Representation of an [AzureDatabaseThreatDetectionPolicy](https://docs.microsoft.com/en-us/rest/api/sql/databasethreatdetectionpolicies). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The resource ID| +|name | The name of the resource.| +|location | The geo-location where the resource lives.| +|kind | The kind of the resource.| +|emailadmins | Specifies that the alert is sent to the account administrators.| +|emailaddresses | Specifies the semicolon-separated list of e-mail addresses to which the alert is sent.| +|retentiondays | Specifies the number of days to keep in the Threat Detection audit logs.| +|state | Specifies the state of the policy.| +|storageendpoint | Specifies the blob storage endpoint.| +|useserverdefault | Specifies whether to use the default server policy.| +|disabledalerts | Specifies the semicolon-separated list of alerts that are disabled, or empty string to disable no alerts.| + +#### Relationships + +- Azure SQL Database contains a Database Threat Detection Policy. + + ``` + (AzureSQLDatabase)-[CONTAINS]->(AzureDatabaseThreatDetectionPolicy) + ``` + +### AzureRestorePoint + +Representation of an [AzureRestorePoint](https://docs.microsoft.com/en-us/rest/api/sql/restorepoints). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The resource ID| +|name | The name of the resource.| +|location | The geo-location where the resource lives.| +|restoredate | The earliest time to which this database can be restored.| +|restorepointtype | The type of restore point.| +|creationdate | The time the backup was taken.| + +#### Relationships + +- Azure SQL Database contains one or more Restore Points. + + ``` + (AzureSQLDatabase)-[CONTAINS]->(AzureRestorePoint) + ``` + +### AzureTransparentDataEncryption + +Representation of an [AzureTransparentDataEncryption](https://docs.microsoft.com/en-us/rest/api/sql/transparentdataencryptions). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The resource ID| +|name | The name of the resource.| +|location | The resource location.| +|status | The status of the database transparent data encryption.| + +#### Relationships + +- Azure SQL Database contains Transparent Data Encryption. + + ``` + (AzureSQLDatabase)-[CONTAINS]->(AzureTransparentDataEncryption) + ``` + +### AzureStorageAccount + +Representation of an [AzureStorageAccount](https://docs.microsoft.com/en-us/rest/api/storagerp/storageaccounts). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| Fully qualified resource ID for the resource.| +|type | The type of the resource.| +|location | The geo-location where the resource lives.| +|resourcegroup | The Resource Group where the storage account is created| +|name | The name of the resource.| +|kind | Gets the Kind of the resource.| +|creationtime | Gets the creation date and time of the storage account in UTC.| +|hnsenabled | Specifies if the Account HierarchicalNamespace is enabled.| +|primarylocation | Gets the location of the primary data center for the storage account.| +|secondarylocation | Gets the location of the geo-replicated secondary for the storage account.| +|provisioningstate | Gets the status of the storage account at the time the operation was called.| +|statusofprimary | Gets the status availability status of the primary location of the storage account.| +|statusofsecondary | Gets the status availability status of the secondary location of the storage account.| +|supportshttpstrafficonly | Allows https traffic only to storage service if sets to true.| + +#### Relationships + +- Azure Subscription contains one or more Storage Accounts. + + ``` + (AzureSubscription)-[RESOURCE]->(AzureStorageAccount) + ``` +- Azure Storage Accounts uses one or more Queue Services. + + ``` + (AzureStorageAccount)-[USES]->(AzureStorageQueueService) + ``` +- Azure Storage Accounts uses one or more Table Services. + + ``` + (AzureStorageAccount)-[USES]->(AzureStorageTableService) + ``` +- Azure Storage Accounts uses one or more File Services. + + ``` + (AzureStorageAccount)-[USES]->(AzureStorageFileService) + ``` +- Azure Storage Accounts uses one or more Blob Services. + + ``` + (AzureStorageAccount)-[USES]->(AzureStorageBlobService) + ``` + +### AzureStorageQueueService + +Representation of an [AzureStorageQueueService](https://docs.microsoft.com/en-us/rest/api/storagerp/queueservices). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| Fully qualified resource ID for the resource.| +|type | The type of the resource.| +|name | The name of the queue service.| + +#### Relationships + +- Azure Storage Accounts uses one or more Queue Services. + + ``` + (AzureStorageAccount)-[USES]->(AzureStorageQueueService) + ``` +- Queue Service contains one or more queues. + + ``` + (AzureStorageQueueService)-[CONTAINS]->(AzureStorageQueue) + ``` + +### AzureStorageTableService + +Representation of an [AzureStorageTableService](https://docs.microsoft.com/en-us/rest/api/storagerp/tableservices). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| Fully qualified resource ID for the resource.| +|type | The type of the resource.| +|name | The name of the table service.| + +#### Relationships + +- Azure Storage Accounts uses one or more Table Services. + + ``` + (AzureStorageAccount)-[USES]->(AzureStorageTableService) + ``` +- Table Service contains one or more tables. + + ``` + (AzureStorageTableService)-[CONTAINS]->(AzureStorageTable) + ``` + +### AzureStorageFileService + +Representation of an [AzureStorageFileService](https://docs.microsoft.com/en-us/rest/api/storagerp/fileservices). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| Fully qualified resource ID for the resource.| +|type | The type of the resource.| +|name | The name of the file service.| + +#### Relationships + +- Azure Storage Accounts uses one or more File Services. + + ``` + (AzureStorageAccount)-[USES]->(AzureStorageFileService) + ``` +- Table Service contains one or more file shares. + + ``` + (AzureStorageFileService)-[CONTAINS]->(AzureStorageFileShare) + ``` + +### AzureStorageBlobService + +Representation of an [AzureStorageBlobService](https://docs.microsoft.com/en-us/rest/api/storagerp/blobservices). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| Fully qualified resource ID for the resource.| +|type | The type of the resource.| +|name | The name of the blob service.| + +#### Relationships + +- Azure Storage Accounts uses one or more Blob Services. + + ``` + (AzureStorageAccount)-[USES]->(AzureStorageBlobService) + ``` +- Blob Service contains one or more blob containers. + + ``` + (AzureStorageBlobService)-[CONTAINS]->(AzureStorageBlobContainer) + ``` + +### AzureStorageQueue + +Representation of an [AzureStorageQueue](https://docs.microsoft.com/en-us/rest/api/storagerp/queue). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| Fully qualified resource ID for the resource.| +|type | The type of the resource.| +|name | The name of the queue.| + +#### Relationships + +- Queue Service contains one or more queues. + + ``` + (AzureStorageQueueService)-[CONTAINS]->(AzureStorageQueue) + ``` + +### AzureStorageTable + +Representation of an [AzureStorageTable](https://docs.microsoft.com/en-us/rest/api/storagerp/table). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| Fully qualified resource ID for the resource.| +|type | The type of the resource.| +|name | The name of the table resource.| +|tablename | Table name under the specified account.| + +#### Relationships + +- Table Service contains one or more tables. + + ``` + (AzureStorageTableService)-[CONTAINS]->(AzureStorageTable) + ``` + +### AzureStorageFileShare + +Representation of an [AzureStorageFileShare](https://docs.microsoft.com/en-us/rest/api/storagerp/fileshares). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| Fully qualified resource ID for the resource.| +|type | The type of the resource.| +|name | The name of the resource.| +|lastmodifiedtime | Specifies the date and time the share was last modified.| +|sharequota | The maximum size of the share, in gigabytes.| +|accesstier | Specifies the access tier for the share.| +|deleted | Indicates whether the share was deleted.| +|accesstierchangetime | Indicates the last modification time for share access tier.| +|accesstierstatus | Indicates if there is a pending transition for access tier.| +|deletedtime | The deleted time if the share was deleted.| +|enabledprotocols | The authentication protocol that is used for the file share.| +|remainingretentiondays | Remaining retention days for share that was soft deleted.| +|shareusagebytes | The approximate size of the data stored on the share.| +|version | The version of the share.| + +#### Relationships + +- File Service contains one or more file shares. + + ``` + (AzureStorageTableService)-[CONTAINS]->(AzureStorageFileShare) + ``` + +### AzureStorageBlobContainer + +Representation of an [AzureStorageBlobContainer](https://docs.microsoft.com/en-us/rest/api/storagerp/blobcontainers). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| Fully qualified resource ID for the resource.| +|type | The type of the resource.| +|name | The name of the resource.| +|deleted | Indicates whether the blob container was deleted.| +|deletedtime | Blob container deletion time.| +|defaultencryptionscope | Default the container to use specified encryption scope for all writes.| +|publicaccess | Specifies whether data in the container may be accessed publicly and the level of access.| +|leasestatus | The lease status of the container.| +|leasestate | Lease state of the container.| +|lastmodifiedtime | Specifies the date and time the container was last modified.| +|remainingretentiondays | Specifies the remaining retention days for soft deleted blob container.| +|version | The version of the deleted blob container.| +|hasimmutabilitypolicy | Specifies the if the container has an ImmutabilityPolicy or not.| +|haslegalhold | Specifies if the container has any legal hold tags.| +|leaseduration | Specifies whether the lease on a container is of infinite or fixed duration, only when the container is leased.| + +#### Relationships + +- Blob Service contains one or more blob containers. + + ``` + (AzureStorageBlobService)-[CONTAINS]->(AzureStorageBlobContainer) + ``` + +### AzureCosmosDBAccount + +Representation of an [AzureCosmosDBAccount](https://docs.microsoft.com/en-us/rest/api/cosmos-db-resource-provider/). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The unique resource identifier of the ARM resource.| +|location | The location of the resource group to which the resource belongs.| +|resourcegroup | The Resource Group where the database account is created.| +|name | The name of the ARM resource.| +|kind | Indicates the type of database account.| +|type | The type of Azure resource.| +|ipranges | List of IpRules.| +|capabilities | List of Cosmos DB capabilities for the account.| +|documentendpoint | The connection endpoint for the Cosmos DB database account.| +|virtualnetworkfilterenabled | Flag to indicate whether to enable/disable Virtual Network ACL rules.| +|enableautomaticfailover | Enables automatic failover of the write region in the rare event that the region is unavailable due to an outage.| +|provisioningstate | The status of the Cosmos DB account at the time the operation was called.| +|multiplewritelocations | Enables the account to write in multiple locations.| +|accountoffertype | The offer type for the Cosmos DB database account.| +|publicnetworkaccess | Whether requests from Public Network are allowed.| +|enablecassandraconnector | Enables the cassandra connector on the Cosmos DB C* account.| +|connectoroffer | The cassandra connector offer type for the Cosmos DB database C* account.| +|disablekeybasedmetadatawriteaccess | Disable write operations on metadata resources (databases, containers, throughput) via account keys.| +|keyvaulturi | The URI of the key vault.| +|enablefreetier | Flag to indicate whether Free Tier is enabled.| +|enableanalyticalstorage | Flag to indicate whether to enable storage analytics.| +|defaultconsistencylevel | The default consistency level and configuration settings of the Cosmos DB account.| +|maxstalenessprefix | When used with the Bounded Staleness consistency level, this value represents the number of stale requests tolerated.| +|maxintervalinseconds | When used with the Bounded Staleness consistency level, this value represents the time amount of staleness (in seconds) tolerated.| + +#### Relationships + +- Azure Subscription contains one or more database accounts. + + ``` + (AzureSubscription)-[RESOURCE]->(AzureCosmosDBAccount) + ``` +- Azure Database Account can be read from, written from and is associated with Azure CosmosDB Locations. + + ``` + (AzureCosmosDBAccount)-[CAN_WRITE_FROM]->(AzureCosmosDBLocation) + ``` + (AzureCosmosDBAccount)-[CAN_READ_FROM]->(AzureCosmosDBLocation) + ``` + (AzureCosmosDBAccount)-[ASSOCIATED_WITH]->(AzureCosmosDBLocation) + ``` +- Azure Database Account contains one or more Cors Policy. + + ``` + (AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBCorsPolicy) + ``` +- Azure Database Account contains one or more failover policies. + + ``` + (AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBAccountFailoverPolicy) + ``` +- Azure Database Account is configured with one or more private endpoint connections. + + ``` + (AzureCosmosDBAccount)-[CONFIGURED_WITH]->(AzureCDBPrivateEndpointConnection) + ``` +- Azure Database Account is configured with one or more virtual network rules. + + ``` + (AzureCosmosDBAccount)-[CONFIGURED_WITH]->(AzureCosmosDBVirtualNetworkRule) + ``` +- Azure Database Account contains one or more SQL databases. + + ``` + (AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBSqlDatabase) + ``` +- Azure Database Account contains one or more Cassandra keyspace. + + ``` + (AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBCassandraKeyspace) + ``` +- Azure Database Account contains one or more MongoDB Database. + + ``` + (AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBMongoDBDatabase) + ``` +- Azure Database Account contains one or more table resource. + + ``` + (AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBTableResource) + ``` + +### AzureCosmosDBLocation + +Representation of an [Azure CosmosDB Location](https://docs.microsoft.com/en-us/rest/api/cosmos-db-resource-provider/). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The unique identifier of the region within the database account.| +|locationname | The name of the region.| +|documentendpoint | The connection endpoint for the specific region.| +|provisioningstate | The status of the Cosmos DB account at the time the operation was called.| +|failoverpriority | The failover priority of the region.| +|iszoneredundant | Flag to indicate whether or not this region is an AvailabilityZone region.| + +#### Relationships + +- Azure Database Account has write permissions from, read permissions from and is associated with Azure CosmosDB Locations. + + ``` + (AzureCosmosDBAccount)-[CAN_WRITE_FROM]->(AzureCosmosDBLocation) + ``` + (AzureCosmosDBAccount)-[CAN_READ_FROM]->(AzureCosmosDBLocation) + ``` + (AzureCosmosDBAccount)-[ASSOCIATED_WITH]->(AzureCosmosDBLocation) + ``` + +### AzureCosmosDBCorsPolicy + +Representation of an [Azure Cosmos DB Cors Policy](https://docs.microsoft.com/en-us/rest/api/cosmos-db-resource-provider/). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The unique resource identifier for Cors Policy.| +|allowedorigins | The origin domains that are permitted to make a request against the service via CORS.| +|allowedmethods | The methods (HTTP request verbs) that the origin domain may use for a CORS request.| +|allowedheaders | The request headers that the origin domain may specify on the CORS request.| +|exposedheaders | The response headers that may be sent in the response to the CORS request and exposed by the browser to the request issuer.| +|maxageinseconds | The maximum amount time that a browser should cache the preflight OPTIONS request.| + +#### Relationships + +- Azure Database Account contains one or more Cors Policy. + + ``` + (AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBCorsPolicy) + ``` + +### AzureCosmosDBAccountFailoverPolicy + +Representation of an Azure Database Account [Failover Policy](https://docs.microsoft.com/en-us/rest/api/cosmos-db-resource-provider/). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The unique identifier of the region in which the database account replicates to.| +|locationname | The name of the region in which the database account exists.| +|failoverpriority | The failover priority of the region. A failover priority of 0 indicates a write region.| + +#### Relationships + +- Azure Database Account contains one or more failover policies. + + ``` + (AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBAccountFailoverPolicy) + ``` + +### AzureCDBPrivateEndpointConnection + +Representation of an Azure Cosmos DB [Private Endpoint Connection](https://docs.microsoft.com/en-us/rest/api/cosmos-db-resource-provider/). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| Fully qualified resource Id for the resource.| +|name | The name of the resource.| +|privateendpointid | Resource id of the private endpoint.| +|status | The private link service connection status.| +|actionrequired | Any action that is required beyond basic workflow (approve/ reject/ disconnect).| + +#### Relationships + +- Azure Database Account is configured with one or more private endpoint connections. + + ``` + (AzureCosmosDBAccount)-[CONFIGURED_WITH]->(AzureCDBPrivateEndpointConnection) + ``` + +### AzureCosmosDBVirtualNetworkRule + +Representation of an Azure Cosmos DB [Virtual Network Rule](https://docs.microsoft.com/en-us/rest/api/cosmos-db-resource-provider/). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| Resource ID of a subnet.| +|ignoremissingvnetserviceendpoint | Create firewall rule before the virtual network has vnet service endpoint enabled.| + +#### Relationships + +- Azure Database Account is configured with one or more virtual network rules. + + ``` + (AzureCosmosDBAccount)-[CONFIGURED_WITH]->(AzureCosmosDBVirtualNetworkRule) + ``` + +### AzureCosmosDBSqlDatabase + +Representation of an [AzureCosmosDBSqlDatabase](https://docs.microsoft.com/en-us/rest/api/cosmos-db-resource-provider/). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The unique resource identifier of the ARM resource.| +|name | The name of the ARM resource.| +|type| The type of Azure resource.| +|location| The location of the resource group to which the resource belongs.| +|throughput| Value of the Cosmos DB resource throughput or autoscaleSettings.| +|maxthroughput| Represents maximum throughput, the resource can scale up to.| + +#### Relationships + +- Azure Database Account contains one or more SQL databases. + + ``` + (AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBSqlDatabase) + ``` +- SQL Databases contain one or more SQL containers. + + ``` + (AzureCosmosDBSqlDatabase)-[CONTAINS]->(AzureCosmosDBSqlContainer) + ``` + +### AzureCosmosDBCassandraKeyspace + +Representation of an [AzureCosmosDBCassandraKeyspace](https://docs.microsoft.com/en-us/rest/api/cosmos-db-resource-provider/). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The unique resource identifier of the ARM resource.| +|name | The name of the ARM resource.| +|type| The type of Azure resource.| +|location| The location of the resource group to which the resource belongs.| +|throughput| Value of the Cosmos DB resource throughput or autoscaleSettings.| +|maxthroughput| Represents maximum throughput, the resource can scale up to.| + +#### Relationships + +- Azure Database Account contains one or more Cassandra keyspace. + + ``` + (AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBCassandraKeyspace) + ``` +- Cassandra Keyspace contains one or more Cassandra tables. + + ``` + (AzureCosmosDBCassandraKeyspace)-[CONTAINS]->(AzureCosmosDBCassandraTable) + ``` + +### AzureCosmosDBMongoDBDatabase + +Representation of an [AzureCosmosDBMongoDBDatabase](https://docs.microsoft.com/en-us/rest/api/cosmos-db-resource-provider/). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The unique resource identifier of the ARM resource.| +|name | The name of the ARM resource.| +|type| The type of Azure resource.| +|location| The location of the resource group to which the resource belongs.| +|throughput| Value of the Cosmos DB resource throughput or autoscaleSettings.| +|maxthroughput| Represents maximum throughput, the resource can scale up to.| + +#### Relationships + +- Azure Database Account contains one or more MongoDB Database. + + ``` + (AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBMongoDBDatabase) + ``` +- MongoDB database contains one or more MongoDB collections. + + ``` + (AzureCosmosDBMongoDBDatabase)-[CONTAINS]->(AzureCosmosDBMongoDBCollection) + ``` + +### AzureCosmosDBTableResource + +Representation of an [AzureCosmosDBTableResource](https://docs.microsoft.com/en-us/rest/api/cosmos-db-resource-provider/). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The unique resource identifier of the ARM resource.| +|name | The name of the ARM resource.| +|type| The type of Azure resource.| +|location| The location of the resource group to which the resource belongs.| +|throughput| Value of the Cosmos DB resource throughput or autoscaleSettings.| +|maxthroughput| Represents maximum throughput, the resource can scale up to.| + +#### Relationships + +- Azure Database Account contains one or more table resource. + + ``` + (AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBTableResource) + ``` + +### AzureCosmosDBSqlContainer + +Representation of an [AzureCosmosDBSqlContainer](https://docs.microsoft.com/en-us/rest/api/cosmos-db-resource-provider/). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The unique resource identifier of the ARM resource.| +|name | The name of the ARM resource.| +|type| The type of Azure resource.| +|location| The location of the resource group to which the resource belongs.| +|throughput| Value of the Cosmos DB resource throughput or autoscaleSettings.| +|maxthroughput| Represents maximum throughput, the resource can scale up to.| +|container| Name of the Cosmos DB SQL container.| +|defaultttl| Default time to live.| +|analyticalttl| Specifies the Analytical TTL.| +|isautomaticindexingpolicy| Indicates if the indexing policy is automatic.| +|indexingmode| Indicates the indexing mode.| +|conflictresolutionpolicymode| Indicates the conflict resolution mode.| + +#### Relationships + +- SQL Databases contain one or more SQL containers. + + ``` + (AzureCosmosDBSqlDatabase)-[CONTAINS]->(AzureCosmosDBSqlContainer) + ``` + +### AzureCosmosDBCassandraTable + +Representation of an [AzureCosmosDBCassandraTable](https://docs.microsoft.com/en-us/rest/api/cosmos-db-resource-provider/). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The unique resource identifier of the ARM resource.| +|name | The name of the ARM resource.| +|type| The type of Azure resource.| +|location| The location of the resource group to which the resource belongs.| +|throughput| Value of the Cosmos DB resource throughput or autoscaleSettings.| +|maxthroughput| Represents maximum throughput, the resource can scale up to.| +|container| Name of the Cosmos DB Cassandra table.| +|defaultttl| Time to live of the Cosmos DB Cassandra table.| +|analyticalttl| Specifies the Analytical TTL.| + +#### Relationships + +- Cassandra Keyspace contains one or more Cassandra tables. + + ``` + (AzureCosmosDBCassandraKeyspace)-[CONTAINS]->(AzureCosmosDBCassandraTable) + ``` + +### AzureCosmosDBMongoDBCollection + +Representation of an [AzureCosmosDBMongoDBCollection](https://docs.microsoft.com/en-us/rest/api/cosmos-db-resource-provider/). + +| Field | Description | +|-------|-------------| +|firstseen| Timestamp of when a sync job discovered this node| +|lastupdated| Timestamp of the last time the node was updated| +|**id**| The unique resource identifier of the ARM resource.| +|name | The name of the ARM resource.| +|type| The type of Azure resource.| +|location| The location of the resource group to which the resource belongs.| +|throughput| Value of the Cosmos DB resource throughput or autoscaleSettings.| +|maxthroughput| Represents maximum throughput, the resource can scale up to.| +|collectionname| Name of the Cosmos DB MongoDB collection.| +|analyticalttl| Specifies the Analytical TTL.| + +#### Relationships + +- MongoDB database contains one or more MongoDB collections. + + ``` + (AzureCosmosDBMongoDBDatabase)-[CONTAINS]->(AzureCosmosDBMongoDBCollection) + ``` diff --git a/_sources/modules/bigfix/config.md.txt b/_sources/modules/bigfix/config.md.txt new file mode 100644 index 0000000000..6e7eac0020 --- /dev/null +++ b/_sources/modules/bigfix/config.md.txt @@ -0,0 +1,10 @@ +## BigFix Configuration + +.. _bigfix_config: + +Follow these steps to analyze BigFix objects with Cartography. + +1. Prepare a read-only BigFix username and password. +1. Pass the BigFix username to the `--bigfix-username` CLI arg. +1. Populate an environment variable with the password. +1. Pass that env var name to the `--bigfix_password_env_var` CLI arg. diff --git a/_sources/modules/bigfix/index.rst.txt b/_sources/modules/bigfix/index.rst.txt new file mode 100644 index 0000000000..ba874d3989 --- /dev/null +++ b/_sources/modules/bigfix/index.rst.txt @@ -0,0 +1,12 @@ +Lastpass +######## + +The BigFix module has the following coverage: + +* Computers + +.. toctree:: + :hidden: + :glob: + + * diff --git a/_sources/modules/bigfix/schema.md.txt b/_sources/modules/bigfix/schema.md.txt new file mode 100644 index 0000000000..5f07b4b099 --- /dev/null +++ b/_sources/modules/bigfix/schema.md.txt @@ -0,0 +1,49 @@ +## BigFix Schema + +.. _bigfix_schema: + + +### BigfixComputer + +Represents a computer tracked by BigFix. + +| Field | Description | +|-------|--------------| +| firstseen| Timestamp of when a sync job first created this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | String. Internal BigFix ID. | +| activedirectorypath | Example: CN=my-server-2,CN=Computers,DC=example-corp,DC=net | +| agenttype | Example: Native | +| agentversion | Version of the BigFix agent. Example: 10.0.7.52 | +| averageevaluationcycle | Example: 106 (integer)| +| besrelayselectionmethod | Example: Manual | +| besrootserver | Example: bigfixroot.example.com (0) | +| bios | String value. Example: 06/25/2021 | +| computername | Example: my-server-2 | +| computertype | Example: Virtual, Physical | +| cpu | Example: 2300 MHz Xeon Gold 5218 | +| devicetype | Example: Server | +| dnsname | Example: my-server-2.example.com | +| enrollmentdatetime | The date time this asset was enrolled in BigFix. Example: 2022-04-06T18:54:01-07:00 | +| ipaddress | Example: 192.168.128.215 | +| ipv6address | Example: fe80:0:0:0:abcd:abcd:abcd:abcd | +| islocked | Boolean - whether this asset is locked | +| lastreporttime | Last reported datetime of this asset 2023-04-19T15:55:23Z | +| locationbyiprange | Example: SF | +| loggedonuser | Currently logged on username. Example: , bartsimpson | +| macaddress | Example: 00-50-ab-cd-ab-cd | +| os | Example: Win2019 10.0.17763.3406 (1809) | +| providername | Example: VMware, On Premises | +| ram | Example: 16384 MB | +| relay | Example: mybigfixrelay.example.com | +| remotedesktopisenabled | Boolean - whether remote desktop is enabled | +| subnetaddress | Example: 192.168.128.0 | +| username | Example: , bartsimpson | + + +#### Relationships + +- A BigfixComputer is a resource of a BigfixRoot. + ``` + (:BigfixRoot)-[:RESOURCE]->(:BigfixComputer) + ``` diff --git a/_sources/modules/crowdstrike/config.md.txt b/_sources/modules/crowdstrike/config.md.txt new file mode 100644 index 0000000000..cd89740414 --- /dev/null +++ b/_sources/modules/crowdstrike/config.md.txt @@ -0,0 +1,11 @@ +## Crowdstrike Configuration + +.. _crowdstrike_config: + +Follow these steps to analyze Crowdstrike falcon objects in Cartography. + +1. Prepare an API key for crowdstrike falcon + 1. Crowdstrike's documentation is private, so please see your instance's documentation on how to generate an API key. + 1. Populate an environment variable with the Client ID. You can pass the environment variable name via CLI with the `--crowdstrike-client-id-env-var` parameter. + 1. Populate an environment variable with the Client Secret. You can pass the environment variable name via CLI with the `--crowdstrike-client-secret-env-var` parameter. + 1. If you are using a self-hosted version of crowdstrike, you can change the API url, by passing it into the CLI with the `--crowdstrike-api-url` parameter. diff --git a/_sources/modules/crowdstrike/index.rst.txt b/_sources/modules/crowdstrike/index.rst.txt new file mode 100644 index 0000000000..e3ca2f96b1 --- /dev/null +++ b/_sources/modules/crowdstrike/index.rst.txt @@ -0,0 +1,14 @@ +Crowdstrike +########### + +The crowdstrike module has the following coverage: + +* Hosts +* Spotlight Vulnerabilities +* CVEs + +.. toctree:: + :hidden: + :glob: + + * diff --git a/_sources/modules/crowdstrike/schema.md.txt b/_sources/modules/crowdstrike/schema.md.txt new file mode 100644 index 0000000000..2c634155f7 --- /dev/null +++ b/_sources/modules/crowdstrike/schema.md.txt @@ -0,0 +1,103 @@ +## Crowdstrike Schema + +.. _crowdstrike_schema: + +### CrowdstrikeHost + +Representation of a Crowdstrike Host + +| Field | Description | +|-------|-------------| +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The device ID for this host | +| cid | The customer ID | +| instance\_id | The AWS instance ID associated with this host | +| status | Containment Status of the machine. "Normal" denotes good operations; other values might mean reduced functionality or support. | +| hostname | The name of the machine. | +| machine\_domain | Active Directory domain name. | +| crowdstrike\_first\_seen | Timestamp of device’s first connection to Falcon | +| crowdstrike\_last\_seen | Timestamp of device’s most recent connection to Falcon | +| local\_ip | The device's local IP address. | +| external\_ip | External IP of the device, as seen by CrowdStrike. | +| cpu\_signature | The CPU signature of the device. | +| bios\_manufacturer | Bios manufacture name. | +| bios\_version | Bios version. | +| mac\_address | The MAC address of the device | +| os\_version | Operating system version. | +| os\_build | The build of the OS | +| platform\_id | CrowdStrike agent configuration notes | +| platform\_name | Operating system platform. | +| service\_provider | The service provider for the device. | +| service\_provider\_account\_id | The service provider account ID associated with this device | +| agent\_version | CrowdStrike agent configuration notes | +| system\_manufacturer | Name of system manufacturer | +| system\_product\_name | Name of system product | +| product\_type | The product type | +| product\_type\_desc | Name of product type. | +| provision\_status | The provision status of the device | +| reduced\_functionality\_mode | Reduced functionality mode (RFM) status | +| kernel\_version | Kernel version of the host OS. | +| major\_version | Major version of the Operating System | +| minor\_version | Minor version of the Operating System | +| tags | Grouping tags for the device | +| modified\_timestamp | The last time that the machine record was updated. Can include status like containment status changes or configuration group changes | + +#### Relationships + +- CrowdstrikeHost has SpotlightVulnerability + ``` + (CrowdstrikeHost)-[HAS_VULNERABILITY]->(SpotlightVulnerability) + ``` + +### SpotlightVulnerability + +Representation of a Crowdstrike Vulnerability + +| Field | Description | +|-------|-------------| +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The ID for this vulnerability | +| cid | The customer ID | +| aid | The unique identifier (agent ID) of the sensor where the vulnerability was found. | +| status | The vulnerability’s current status. One of open, closed, reopen, or expired. | +| created\_timestamp | The UTC date and time that the vulnerability was created in Spotlight. | +| closed\_timestamp | The date and time a vulnerability was set to a status of "closed" | +| updated\_timestamp | The UTC date and time of the last update made on a vulnerability. | +| cve\_id | The ID of the CVE. | +| host\_info\_local\_ip | The device’s local IP address. | +| remediation\_ids | The unique IDs of the remediations. | +| app\_product\_name\_version | The name and version of the product associated with the vulnerability. | + +#### Relationships + +- CrowdstrikeHost has SpotlightVulnerability + ``` + (CrowdstrikeHost)-[HAS_VULNERABILITY]->(SpotlightVulnerability) + ``` + +- SpotlightVulnerability has CVE + ``` + (SpotlightVulnerability)-[HAS_CVE]->(CVE) + ``` + +### CVE::CrowdstrikeFinding + +Representation of a CVE + +| Field | Description | +|-------|-------------| +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The ID for this CVE | +| base\_score | Base score of the CVE (float value between 1 and 10). | +| severity | Severity of the CVE. One of CRITICAL, HIGH, MEDIUM, LOW, UNKNOWN, or NONE. | +| exploitability\_score | Numeric value of the most severe known exploit. 0=UNPROVEN; 30=AVAILABLE; 60=EASILY\_ACCESSIBLE; 90=ACTIVELY\_USED | + +#### Relationships + +- SpotlightVulnerability has CVE + ``` + (SpotlightVulnerability)-[HAS_CVE]->(CVE) + ``` diff --git a/_sources/modules/crxcavator/config.md.txt b/_sources/modules/crxcavator/config.md.txt new file mode 100644 index 0000000000..025db1fdab --- /dev/null +++ b/_sources/modules/crxcavator/config.md.txt @@ -0,0 +1,12 @@ +## Crxcavator Configuration + +.. _crxcavator_config: + +Follow these steps to analyze Chrome Extensions with Cartography. + +1. **Prepare your CRXcavator API key** + + 1. Generate an API key from your CRXcavator [user page](https://crxcavator.io/user/settings#) + 1. Add the required commandline arguments when calling Cartography + 1. `--crxcavator-api-base-url` - the full URL to the CRXcavator API. https://api.crxcavator.io/v1 as of 01/16/2020 (this value will be used if not provided) + 1. `--crxcavator-api-key-env-var` - Name of environment variable holding your API key generated in the previous step. Note this is a credential and should be stored in an appropriate secret store to be populated securely into your runtime environment. diff --git a/_sources/modules/crxcavator/index.rst.txt b/_sources/modules/crxcavator/index.rst.txt new file mode 100644 index 0000000000..e74b2e04e1 --- /dev/null +++ b/_sources/modules/crxcavator/index.rst.txt @@ -0,0 +1,13 @@ +Duo CRXcavator +############## + +The crxcavator module has the following coverage: + +* Chrome extensions +* GSuite users + +.. toctree:: + :hidden: + :glob: + + * diff --git a/_sources/modules/crxcavator/schema.md.txt b/_sources/modules/crxcavator/schema.md.txt new file mode 100644 index 0000000000..3029ecb59c --- /dev/null +++ b/_sources/modules/crxcavator/schema.md.txt @@ -0,0 +1,67 @@ +## Crxcavtor Schema + +### GSuiteUser + +Placeholder representation of a single G Suite [user object](https://developers.google.com/admin-sdk/directory/v1/reference/users). This node is the minimal data necessary to map who has extensions installed until full G Suite data is imported. + + +| Field | Description | +|-------|--------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The user's email address, will change to actual G Suite id in future | +| email | The user's email address + +#### Relationships + +- GSuiteUsers install ChromeExtensions. + + ``` + (GSuiteUser)-[INSTALLS]->(ChromeExtension) + ``` + +### ChromeExtension + + Representation of a CRXcavator Chrome Extension [Report](https://crxcavator.io/apidocs#tag/report). + +| Field | Description | +|-------|--------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The combined extension name and version e.g. ``"Docs\|1.0"`` | +| extension\_id | CRXcavator id for extension. | +| version | The versions of the extension in this report | +| risk\_total | CRXcavator risk score for the extension | +| risk\_metadata | Additional data provided by CRXcavator on the risk score | +| risk\_permissions\_score | Sum of the permissions component of the risk score | +| risk\_webstore\_score | Sum of the webstore component of the risk score | +| risk\_csp\_score | Sum of the CSP component of the risk score | +| risk\_optional\_permissions\_score | Sum of the optional permissions component of the risk score | +| risk\_extcalls\_score | Sum of the external calls component of the risk score | +| risk\_vuln\_score | Sum of the RetireJS vulnerability component of the risk score | +| address | Physical address of extension developer | +| email | Email address of extension developer | +| icon | URL of the extension icon | +| crxcavator\_last\_updated | Date the extension was last updated in the webstore | +| name | Full name of the extension | +| offered\_by | Name of the extension developer | +| permissions\_warnings | Concatenated list of permissions warnings for the extension | +| privacy\_policy | URL of privacy policy for extension | +| rating | Current webstore rating for extension | +| rating\_users | How many users have provided a rating for the extension | +| short\_description | Summary of what extension does | +| size | Size of extension download | +| support\_site | URL of developer support site | +| users | Webstore count of extension users | +| website | Developer URL for extension | +| type | Extension categorization | +| price | Extension price in webstore if applicable | +| report\_link | URL of full extension report on crxcavator.io | + +#### Relationships + +- GSuiteUsers install ChromeExtensions. + + ``` + (GSuiteUser)-[INSTALLS]->(ChromeExtension) + ``` diff --git a/_sources/modules/cve/config.md.txt b/_sources/modules/cve/config.md.txt new file mode 100644 index 0000000000..8a5cb67b27 --- /dev/null +++ b/_sources/modules/cve/config.md.txt @@ -0,0 +1,8 @@ +## CVE Configuration + +.. _cve_config: + +Follow these steps to analyze CVE objects with Cartography. + +1. Call cartography with the `--enable-cve` flag. +1. If you are mirroring the CVE data, and wish to change the base url, you can pass the base url into the cli with the `--nist-cve-url` flag. diff --git a/_sources/modules/cve/index.rst.txt b/_sources/modules/cve/index.rst.txt new file mode 100644 index 0000000000..72981da2b9 --- /dev/null +++ b/_sources/modules/cve/index.rst.txt @@ -0,0 +1,12 @@ +CVE +### + +The CVE module has the following coverage: + +* CVE data, as defined by the v4 JSON CVE format + +.. toctree:: + :hidden: + :glob: + + * diff --git a/_sources/modules/cve/schema.md.txt b/_sources/modules/cve/schema.md.txt new file mode 100644 index 0000000000..5fb78a2ee3 --- /dev/null +++ b/_sources/modules/cve/schema.md.txt @@ -0,0 +1,36 @@ +## CVE Schema + +.. _cve_schema: + +### CVE + +Representation of a [CVE](https://github.com/CVEProject/automation-working-group/blob/master/cve_json_schema/DRAFT-JSON-file-format-v4.md) + +| Field | Description | +|-------|--------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The CVE ID | +| assigner | The assigner of the CVE (email address) | +| description\_en | The english description of the issue. | +| references | This is reference data in the form of URLs | +| problem\_types | A list of CWE identifiers | +| vector\_string | The CVSSv3 scoring data. | +| attack\_vector | The attack vector | +| attack\_complexity | The attack complexity | +| privileges\_required | The privileges required | +| user\_interaction | The user interaction | +| scope | The scope | +| confidentiality\_impact | The confidentiality impact | +| integrity\_impact | The integrity impact | +| availability\_impact | The availability impact | +| base\_score | The CVSSv3 score | +| base\_severity | The severity | +| exploitability\_score | The exploitability score | +| impact\_score | The impact score | +| published\_date | The date the CVE was published | +| last\_modified\_date | The date the CVE was last updated | + +#### Relationships + +None diff --git a/_sources/modules/digitalocean/config.md.txt b/_sources/modules/digitalocean/config.md.txt new file mode 100644 index 0000000000..50b553fb3d --- /dev/null +++ b/_sources/modules/digitalocean/config.md.txt @@ -0,0 +1,15 @@ +## Configuration + +.. _digitalocean_config: + +Follow these steps to analyze GitHub repos and other objects with Cartography. + +1. Prepare your DigitalOcean credentials. Visit [official docs](https://cloud.digitalocean.com/account/api/tokens) for +more up to date info. + 1. Login into your DigitalOcean Account + 1. Visit Account -> API -> Tokens section + 1. Click on `Generate New Token` to create a personal access token + 1. Make sure the scope of the token is set to `READ` +1. Populate an environment variable of your choice with the access token generated in the previous step. +1. Call the `cartography` CLI with `--digitalocean-token-env-var YOUR_ENV_VAR_HERE`. +1. `Cartography` will then load your graph with data from the account linked to the token you specified. diff --git a/_sources/modules/digitalocean/index.rst.txt b/_sources/modules/digitalocean/index.rst.txt new file mode 100644 index 0000000000..174fcd09f8 --- /dev/null +++ b/_sources/modules/digitalocean/index.rst.txt @@ -0,0 +1,14 @@ +DigitalOcean +############ + +The digitalocean module has the following coverage: + +* Accounts +* Projects +* Compute - Droplets + +.. toctree:: + :hidden: + :glob: + + * diff --git a/_sources/modules/digitalocean/schema.md.txt b/_sources/modules/digitalocean/schema.md.txt new file mode 100644 index 0000000000..699b4a5705 --- /dev/null +++ b/_sources/modules/digitalocean/schema.md.txt @@ -0,0 +1,82 @@ +## DigitalOcean Schema + +.. _digitalocean_schema: + +### DOAccount +Representation of a DigitalOcean [Account](https://developers.digitalocean.com/documentation/v2/#account) object. + +| Field | Description | +| ----- | ----------- | +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The UUID of the account | +| uuid | The UUID of the account (same value as id) | +| droplet_limit | Total number of droplets that the account can have at one time | +| floating_ip_limit | Total number of floating IPs the account may have | +| status | Status of the account | + +#### Relationships + +- DOAccount contains DOProjects. + + ``` + (DOAccount)-[RESOURCE]->(DOProjects) + ``` + +### DOProject +Representation of a DigitalOcean [Project](https://developers.digitalocean.com/documentation/v2/#projects) object. + +| Field | Description | +| ----- | ----------- | +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The unique universal identifier of the project | +| account_id | Id of the DOAccount where this project belongs to | +| description | The description of the project | +| environment | The environment of the project's resources | +| is_default | If true, all resources will be added to this project if no project is specified | +| name | The human-readable name for the project | +| owner_uuid | The unique universal identifier of the project's owner | +| created_at | A time value given in ISO8601 combined date and time format that represents when the project was created | +| updated_at | A time value given in ISO8601 combined date and time format that represents when the project was updated | + +#### Relationships + +- DOProject has DODroplets as resource. + + ``` + (DOProject)-[RESOURCE]->(DODroplet) + ``` + +### DODroplet +Representation of a DigitalOcean [Droplet](https://developers.digitalocean.com/documentation/v2/#droplets) object. + +| Field | Description | +| ----- | ----------- | +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | A unique identifier for each Droplet instance | +| account_id | Id of the DOAccount where this Droplet belongs to | +| features | An array of features enabled on this Droplet | +| locked | A boolean value indicating whether the Droplet has been locked, preventing actions by users | +| image | The slug of the base image used to create the Droplet instance| +| ip_address | The v4 external ip address of this Droplet | +| ip_v6_address | The v6 external ip address of this Droplet | +| kernel | The current kernel image id| +| name | The human-readable name set for the Droplet instance | +| private_ip_address | The v4 internal ip address of this Droplet | +| project_id | Id of the DOProject where this Droplet belongs to | +| region | The region that the Droplet instance is deployed in | +| size | The current size object describing the Droplet | +| status | A status string indicating the state of the Droplet instance.This may be "new", "active", "off", or "archive"| +| tags | An array of Tags the Droplet has been tagged with | +| volumes | A flat array including the unique identifier for each Block Storage volume attached to the Droplet | +| created_at | A time value given in ISO8601 combined date and time format that represents when the Droplet was created | + +#### Relationships + +- DODroplet is a resource of a DOProject. + + ``` + (DODroplet)<-[RESOURCE]-(DOProject) + ``` diff --git a/_sources/modules/duo/config.md.txt b/_sources/modules/duo/config.md.txt new file mode 100644 index 0000000000..724d575e2b --- /dev/null +++ b/_sources/modules/duo/config.md.txt @@ -0,0 +1,10 @@ +## Duo Configuration + +.. _duo_config: + +Follow these steps to analyze Duo objects with Cartography. + +1. Prepare a [admin api creds](https://duo.com/docs/adminapi). +1. Pass the Duo api host name to the `--duo-api-hostname` CLI arg. +1. Populate environment variables with the api key and api secret. +1. Pass that those var names to the `--duo-api-key-env-var` and `--duo-api-secret-env-var` CLI args. diff --git a/_sources/modules/duo/index.rst.txt b/_sources/modules/duo/index.rst.txt new file mode 100644 index 0000000000..16842beeb2 --- /dev/null +++ b/_sources/modules/duo/index.rst.txt @@ -0,0 +1,14 @@ +Duo +#### + +The okta module has the following coverage: + +* Users +* Groups +* Endpoints + +.. toctree:: + :hidden: + :glob: + + * diff --git a/_sources/modules/duo/schema.md.txt b/_sources/modules/duo/schema.md.txt new file mode 100644 index 0000000000..0e648de3da --- /dev/null +++ b/_sources/modules/duo/schema.md.txt @@ -0,0 +1,311 @@ +## Duo Schema + +.. _duo_schema: + +### DuoApiHost + +Represents a Duo API Host to conain Duo resources. + +| Field | Description | +|-------|--------------| +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The hostname | + +#### Relationships + +- An DuoApiHost contains DuoUsers + + ``` + (DuoApiHost)-[RESOURCE]->(DuoUser) + ``` + +- An DuoApiHost contains DuoGroups + + ``` + (DuoApiHost)-[RESOURCE]->(DuoGroup) + ``` + +- An DuoApiHost contains DuoEndpoints + + ``` + (DuoApiHost)-[RESOURCE]->(DuoEndpoint) + ``` + +- An DuoApiHost contains DuoPhones + + ``` + (DuoApiHost)-[RESOURCE]->(DuoPhone) + ``` + +- An DuoApiHost contains DuoTokens + + ``` + (DuoApiHost)-[RESOURCE]->(DuoToken) + ``` + +- An DuoApiHost contains DuoWebAuthnCredentials + + ``` + (DuoApiHost)-[RESOURCE]->(DuoWebAuthnCredential) + ``` + +### DuoGroup + +Represents a [group](https://duo.com/docs/adminapi#groups) in Duo. + +| Field | Description | +|-------|--------------| +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The user_id | +| desc | The group's description. | +| group_id | The group's ID. | +| mobile_otp_enabled | Legacy parameter; no effect if specified and always returns false. | +| name | The group's name. If managed by directory sync, then the name returned here also indicates the source directory. | +| push_enabled | Legacy parameter; no effect if specified and always returns false. | +| sms_enabled | Legacy parameter; no effect if specified and always returns false | +| status | The group's authentication status. May be one of: "Active", "Bypass", "Disabled" | +| voice_enabled | Legacy parameter; no effect if specified and always returns false | + +#### Relationships + +- An DuoApiHost contains DuoGroups + + ``` + (DuoApiHost)-[RESOURCE]->(DuoGroup) + ``` + +- A DuoUser is part of multiple DuoGroups. + + ``` + (DuoUser)-[MEMBER_OF_DUO_GROUP]->(DuoGroup) + ``` + + +### DuoUser + +Represents a [user](https://duo.com/docs/adminapi#users) in Duo. + +| Field | Description | +|-------|--------------| +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The user_id | +| alias1 | The user's username alias1. | +| alias2 | The user's username alias2. | +| alias3 | The user's username alias3. | +| alias4 | The user's username alias4. | +| aliases | Map of the user's username alias(es). Up to eight aliases may exist. | +| created | The user's creation date as a UNIX timestamp. | +| email | The user's email address. | +| firstname | The user's given name. | +| groups | List of groups to which this user belongs. See Retrieve Groups for response info. | +| is_enrolled | Is true if the user has a phone, hardware token, U2F token, WebAuthn security key, or other WebAuthn method available for authentication. Otherwise, false. | +| last_directory_sync | An integer indicating the last update to the user via directory sync as a Unix timestamp, or null if the user has never synced with an external directory or if the directory that originally created the user has been deleted from Duo. | +| last_login | An integer indicating the last time this user logged in, as a Unix timestamp, or null if the user has not logged in. | +| lastname | The user's surname. | +| notes | Notes about this user. Viewable in the Duo Admin Panel. | +| realname | The user's real name (or full name). | +| status | The user's status. One of: "active", "bypass", "disabled", "locked out", "pending deletion". | +| tokens | A list of tokens that this user can use. A list of JSON strings | +| u2f_tokens | A list of U2F tokens that this user can use. A list of JSON strings | +| user_id | The user's ID. | +| username | The user's username. | +| webauthncredentials | A list of WebAuthn authenticators that this user can use. A list of JSON strings | + +#### Relationships + +- An DuoApiHost contains DuoUsers + + ``` + (DuoApiHost)-[RESOURCE]->(DuoUser) + ``` + +- A DuoUser is part of multiple DuoGroups. + + ``` + (DuoUser)-[MEMBER_OF_DUO_GROUP]->(DuoGroup) + ``` + +- A DuoUser has multiple DuoEndpoints + + ``` + (DuoUser)-[HAS_DUO_ENDPOINT]->(DuoEndpoint) + ``` + +- A DuoUser has multiple DuoPhones + + ``` + (DuoUser)-[HAS_DUO_PHONE]->(DuoPhone) + ``` + +- A DuoUser has multiple DuoTokens + + ``` + (DuoUser)-[HAS_DUO_TOKEN]->(DuoToken) + ``` + +- A DuoUser has multiple WebAuthnCredentials + + ``` + (DuoUser)-[HAS_DUO_WEB_AUTHN_CREDENTIAL]->(WebAuthnCredential) + ``` + +- A DuoUser is an identity to a Human + + ``` + (DuoUser)<-[IDENTITY_DUO]-(Human) + ``` + +### DuoEndpoint + +Represents a [endpoint](https://duo.com/docs/adminapi#endpoints) in Duo. + +| Field | Description | +|-------|--------------| +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The epkey | +| browsers | Collected information about all detected browsers on an individual endpoint. A list of JSON strings | +| computer_sid | The machine security identifier of a Windows endpoint. | +| cpu_id | The CPU ID of a Windows endpoint. | +| device_id | Custom device identifier of a Meraki-managed iOS endpoint. Returned for Duo Premier customers only. | +| device_identifier | The unique device attribute value that identifies the endpoint. Returned for Duo Premier customers only. This property will be deprecated in a future release. | +| device_identifier_type | The device attribute used to identify a unique endpoint. One of "hardware_uuid", "fqdn", "hardware_serial", "device_udid", or none. This property will be deprecated in a future release. | +| device_name | The endpoint's hostname. | +| device_udid | The unique device identifier for iOS endpoints managed by Workspace ONE, MobileIron Cloud or Core, or Sophos Mobile via certificates. Returned for Duo Premier customers only. | +| device_username | The unique attribute value that identifies the endpoint's associated user in the management system. Returned for Duo Premier customers only. | +| device_username_type | The management system attribute used to identify the user associated with the unique endpoint. One of "os_username", "upn", "username", "email", or none. Returned for Duo Premier customers only. | +| disk_encryption_status | The hard drive encryption status of the endpoint as detected by the Duo Device Health app. One of "On", "Off", or "Unknown". | +| domain_sid | The Active Directory domain security identifier for a domain-joined Windows endpoint. Empty if the Windows endpoint is not joined to a domain. | +| email | The email address, if present, of the user associated with an endpoint. | +| epkey | The endpoint's unique identifier. | +| firewall_status | Status of the endpoint's local firewall as detected by the Duo Device Health app. One of "On", "Off", or "Unknown". | +| hardware_uuid | The universally unique identifier for a Mac endpoint. | +| health_app_client_version | The version of the Duo Device Health app installed on the endpoint. | +| health_data_last_collected | The last time the Duo Device Health app performed a device health check, as a Unix timestamp. | +| last_updated | The last time the endpoint accessed Duo, as a Unix timestamp. | +| machine_guid | The globally unique identifier for a Windows endpoint. | +| model | The device model of a 2FA endpoint. | +| os_build | The endpoint's operating system build number. | +| os_family | The endpoint's operating system platform. | +| os_version | The endpoint's operating system version. | +| password_status | Whether the local admin password is set on the endpoint as detected by the Duo Device Health app. One of "Set", "Unset", or "Unknown" | +| security_agents | Information about security agents present on the endpoint as detected by the Duo Device Health app. Returned for Duo Premier customers only. a list of JSON strings | +| trusted_endpoint | Whether the endpoint is a Duo managed endpoint. One of "yes", "no", or "unknown". Returned for Duo Premier customers only. | +| type | The endpoint's device class. | +| username | The Duo username of the user associated with an endpoint. | + + +#### Relationships + +- An DuoApiHost contains DuoEndpoints + + ``` + (DuoApiHost)-[RESOURCE]->(DuoEndpoint) + ``` + +- A DuoUser has multiple DuoEndpoints + + ``` + (DuoUser)-[HAS_DUO_ENDPOINT]->(DuoEndpoint) + ``` + +### DuoPhone + +Represents a [phone](https://duo.com/docs/adminapi#phones) in Duo. + +| Field | Description | +|-------|--------------| +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The phone_id | +| activated | Has this phone been activated for Duo Mobile yet? Either true or false. | +| capabilities | List of strings, each a factor that can be used with the device. Any of "auto", "push", "pphone", "sms", "mobile_otp" | +| encrypted | The encryption status of an Android or iOS device file system. One of: "Encrypted", "Unencrypted", or "Unknown". Blank for other platforms. | +| extension | An extension, if necessary. | +| fingerprint | Whether an Android or iOS phone is configured for biometric verification. One of: "Configured", "Disabled", or "Unknown". Blank for other platforms. | +| last_seen | An integer indicating the timestamp of the last contact between Duo's service and the activated Duo Mobile app installed on the phone. Blank if the device has never activated Duo Mobile or if the platform does not support it. | +| model | The phone's model. | +| name | Free-form label for the phone. | +| phone_id | The phone's ID. | +| platform | The phone platform. One of: "unknown", "google android", "apple ios", "windows phone 7", "rim blackberry", "java j2me", "palm webos", "symbian os", "windows mobile", or "generic smartphone" | +| postdelay | The time (in seconds) to wait after the extension is dialed and before the speaking the prompt. | +| predelay | The time (in seconds) to wait after the number picks up and before dialing the extension. | +| screenlock | Whether screen lock is enabled on an Android or iOS phone. One of: "Locked", "Unlocked", or "Unknown". Blank for other platforms. | +| sms_passcodes_sent | Have SMS passcodes been sent to this phone? Either true or false. | +| tampered | Whether an iOS or Android device is jailbroken or rooted. One of: "Not Tampered", "Tampered", or "Unknown". Blank for other platforms. | +| type | The type of phone. One of: "unknown", "mobile", or "landline". | + +#### Relationships + +- An DuoApiHost contains DuoPhone + + ``` + (DuoApiHost)-[RESOURCE]->(DuoPhone) + ``` + +- A DuoUser has multiple DuoPhones + + ``` + (DuoUser)-[HAS_DUO_PHONE]->(DuoPhone) + ``` + +### DuoToken + +Represents a [token](https://duo.com/docs/adminapi#tokens) in Duo. + +| Field | Description | +|-------|--------------| +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The token_id | +| admins | A list of administrators associated with this hardware token. See Retrieve Administrators for descriptions of the response fields. A list of JSON strings | +| serial | The serial number of the hardware token; used to uniquely identify the hardware token when paired with type. | +| token_id | The hardware token's unique ID. | +| totp_step | Value is null for all supported token types. | +| type | The type of hardware token. | + +#### Relationships + +- An DuoApiHost contains DuoTokens + + ``` + (DuoApiHost)-[RESOURCE]->(DuoToken) + ``` + +- A DuoUser has multiple DuoTokens + + ``` + (DuoUser)-[HAS_DUO_TOKEN]->(DuoToken) + ``` + +### DuoWebAuthnCredential + +Represents a [web authn credential](https://duo.com/docs/adminapi#webauthn-credentials) in Duo. + +| Field | Description | +|-------|--------------| +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | The webauthnkey | +| admin |Selected information about the administrator attached to the WebAuthn credential. Returns null if attached to an end user. Not returned if the API application does not have sufficient permission to manage administrators. A JSON string | +| credential_name | Free-form label for the WebAuthn credential. | +| date_added | The date the WebAuthn credential was registered in Duo. | +| label | Indicates the type of WebAuthn credential. One of: "Security Key" or "Touch ID". Present when attached to a user. | +| webauthnkey | The WebAuthn credential's registration identifier. | + +#### Relationships + +- An DuoApiHost contains DuoWebAuthnCredentials + + ``` + (DuoApiHost)-[RESOURCE]->(DuoWebAuthnCredential) + ``` + +- A DuoUser has multiple DuoWebAuthnCredentials + + ``` + (DuoUser)-[HAS_DUO_WEB_AUTHN_CREDENTIAL]->(DuoWebAuthnCredential) + ``` diff --git a/_sources/modules/gcp/config.md.txt b/_sources/modules/gcp/config.md.txt new file mode 100644 index 0000000000..f1a0c7bd93 --- /dev/null +++ b/_sources/modules/gcp/config.md.txt @@ -0,0 +1,21 @@ +## GCP Configuration + +.. _gcp_config: + +Follow these steps to analyze GCP projects with Cartography. + +1. Prepare your GCP credential(s). + + 1. Create an identity - either a User Account or a Service Account - for Cartography to run as + 1. Ensure that this identity has the following roles (https://cloud.google.com/iam/docs/understanding-roles) attached to it: + - `roles/iam.securityReviewer` + - `roles/resourcemanager.organizationViewer`: needed to list/get GCP Organizations + - `roles/resourcemanager.folderViewer`: needed to list/get GCP Folders + 1. Ensure that the machine you are running Cartography on can authenticate to this identity. + - **Method 1**: You can do this by setting your `GOOGLE_APPLICATION_CREDENTIALS` environment variable to point to a json file containing your credentials. As per SecurityCommonSense™️, please ensure that only the user account that runs Cartography has read-access to this sensitive file. + - **Method 2**: If you are running Cartography on a GCE instance or other GCP service, you can make use of the credential management provided by the default service accounts on these services. See the [official docs](https://cloud.google.com/docs/authentication/production) on Application Default Credentials for more details. + +### Multiple GCP Project Setup + +In order for Cartography to be able to pull all assets from all GCP Projects within an Organization, the User/Service Account assigned to Cartography needs to be created at the **Organization** level. +This is because [IAM access control policies applied on the Organization resource apply throughout the hierarchy on all resources in the organization](https://cloud.google.com/resource-manager/docs/cloud-platform-resource-hierarchy#organizations). diff --git a/_sources/modules/gcp/index.rst.txt b/_sources/modules/gcp/index.rst.txt new file mode 100644 index 0000000000..11dce43e29 --- /dev/null +++ b/_sources/modules/gcp/index.rst.txt @@ -0,0 +1,16 @@ +Google Cloud Compute (GCP) +########################## + +The gcp module has the following coverage: + +* Cloud Resource Manager +* Compute +* DNS +* Storage +* Google Kubernetes Engine + +.. toctree:: + :hidden: + :glob: + + * diff --git a/_sources/modules/gcp/schema.md.txt b/_sources/modules/gcp/schema.md.txt new file mode 100644 index 0000000000..daa5999ddf --- /dev/null +++ b/_sources/modules/gcp/schema.md.txt @@ -0,0 +1,639 @@ +## GCP Schema + +### GCPOrganization + +Representation of a GCP [Organization](https://cloud.google.com/resource-manager/reference/rest/v1/organizations) object. + + +| Field | Description | +| -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The name of the GCP Organization, e.g. "organizations/1234" | +| displayname | The "friendly name", e.g. "My Company" | +| lifecyclestate | The organization's current lifecycle state. Assigned by the server. See the [official docs](https://cloud.google.com/resource-manager/reference/rest/v1/organizations#LifecycleState). | + +#### Relationships + +- GCPOrganizations contain GCPFolders. + + ``` + (GCPOrganization)-[RESOURCE]->(GCPFolder) + ``` + +- GCPOrganizations can contain GCPProjects. + + ``` + (GCPOrganization)-[RESOURCE]->(GCPProjects) + ``` + +### GCPFolder + + Representation of a GCP [Folder](https://cloud.google.com/resource-manager/reference/rest/v2/folders). An additional helpful reference is the [Google Compute Platform resource hierarchy](https://cloud.google.com/resource-manager/docs/cloud-platform-resource-hierarchy). + +| Field | Description | +| -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The name of the folder, e.g. "folders/1234" | +| displayname | A friendly name of the folder, e.g. "My Folder". | +| lifecyclestate | The folder's current lifecycle state. Assigned by the server. See the [official docs](https://cloud.google.com/resource-manager/reference/rest/v2/folders#LifecycleState). | + + +#### Relationships + + - GCPOrganizations are parents of GCPFolders. + + ``` + (GCPOrganization)<-[PARENT]-(GCPFolder) + ``` + + - GCPFolders can contain GCPProjects + + ``` + (GCPFolder)-[RESOURCE]->(GCPProject) + ``` + + - GCPFolders can contain other GCPFolders. + + ``` + (GCPFolder)-[RESOURCE]->(GCPFolder) + ``` + +### GCPProject + + Representation of a GCP [Project](https://cloud.google.com/resource-manager/reference/rest/v1/projects). An additional helpful reference is the [Google Compute Platform resource hierarchy](https://cloud.google.com/resource-manager/docs/cloud-platform-resource-hierarchy). + + | Field | Description | + | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | + | firstseen | Timestamp of when a sync job first discovered this node | + | lastupdated | Timestamp of the last time the node was updated | + | id | The ID of the project, e.g. "sys-12345" | + | projectnumber | The number uniquely identifying the project, e.g. '987654' | + | displayname | A friendly name of the project, e.g. "MyProject". | + | lifecyclestate | The project's current lifecycle state. Assigned by the server. See the [official docs](https://cloud.google.com/resource-manager/reference/rest/v1/projects#LifecycleState). | + + ### Relationships + +- GCPOrganizations contain GCPProjects. + + ``` + (GCPOrganization)-[RESOURCE]->(GCPProjects) + ``` + + - GCPFolders can contain GCPProjects + + ``` + (GCPFolder)-[RESOURCE]->(GCPProject) + ``` + +- GCPVpcs are part of GCPProjects + + ``` + (GCPProject)-[RESOURCE]->(GCPVpc) + ``` + + +### GCPBucket +Representation of a GCP [Storage Bucket](https://cloud.google.com/storage/docs/json_api/v1/buckets). + +| Field | Description | +| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The ID of the storage bucket, e.g. "bucket-12345" | +| projectnumber | The number uniquely identifying the project associated with the storage bucket, e.g. '987654' | +| self_link | The URI of the storage bucket | +| kind | The kind of item this is. For storage buckets, this is always storage#bucket | +| location | The location of the bucket. Object data for objects in the bucket resides in physical storage within this region. Defaults to US. See [Cloud Storage bucket locations](https://cloud.google.com/storage/docs/locations) for the authoritative list. | +| location_type | The type of location that the bucket resides in, as determined by the `location` property | +| meta_generation | The metadata generation of this bucket | +| storage_class | The bucket's default storage class, used whenever no `storageClass` is specified for a newly-created object. For more information, see [storage classes](https://cloud.google.com/storage/docs/storage-classes) | +| time_created | The creation time of the bucket in RFC 3339 format | +| retention_period | The period of time, in seconds, that objects in the bucket must be retained and cannot be deleted, overwritten, or archived | +| iam_config_bucket_policy_only | The bucket's [Bucket Policy Only](https://cloud.google.com/storage/docs/bucket-policy-only) configuration | +| owner_entity | The entity, in the form `project-owner-projectId` | +| owner_entity_id | The ID for the entity | +| versioning_enabled | The bucket's versioning configuration (if set to `True`, versioning is fully enabled for this bucket) | +| log_bucket | The destination bucket where the current bucket's logs should be placed | +| requester_pays | The bucket's billing configuration (if set to true, Requester Pays is enabled for this bucket) | +| default_kms_key_name | A Cloud KMS key that will be used to encrypt objects inserted into this bucket, if no encryption method is specified | + +#### Relationships + +- GCPBuckets are part of GCPProjects. + + ``` + (GCPProject)-[RESOURCE]->(GCPBucket) + ``` + +- GCPBuckets can be labelled with GCPBucketLabels. + + ``` + (GCPBucket)<-[LABELLED]-(GCPBucketLabels) + ``` + + +### GCPDNSZone + +Representation of a GCP [DNS Zone](https://cloud.google.com/dns/docs/reference/v1/). + +| Field | Description | +| ---------- | ------------------------------------------------------- | +| created_at | The date and time the zone was created | +| description | An optional description of the zone| +| dns_name | The DNS name of this managed zone, for instance "example.com.". +| firstseen | Timestamp of when a sync job first discovered this node | +| **id** |Unique identifier| +| name | The name of the zone | +| nameservers |Virtual name servers the zone is delegated to +| visibility | The zone's visibility: `public` zones are exposed to the Internet, while `private` zones are visible only to Virtual Private Cloud resources.| + + +#### Relationships + +- GKEClusters are resources of GCPProjects. + + ``` + (GCPProject)-[RESOURCE]->(GCPDNSZone) + ``` + + +### Label: GCPBucketLabel +Representation of a GCP [Storage Bucket Label](https://cloud.google.com/storage/docs/key-terms#bucket-labels). This node contains a key-value pair. + + | Field | Description | + | ----------- | ------------------------------------------------------------------- | + | firstseen | Timestamp of when a sync job first discovered this node | + | lastupdated | Timestamp of the last time the node was updated | + | id | The ID of the bucket label. Takes the form "GCPBucketLabel\_{key}." | + | key | The key of the bucket label. | + | value | The value of the bucket label. | + +- GCPBuckets can be labeled with GCPBucketLabels. + + ``` + (GCPBucket)<-[LABELED]-(GCPBucketLabels) + ``` + + +### GCPInstance + +Representation of a GCP [Instance](https://cloud.google.com/compute/docs/reference/rest/v1/instances). Additional references can be found in the [official documentation]( https://cloud.google.com/compute/docs/concepts). + +| Field | Description | +| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The partial resource URI representing this instance. Has the form `projects/{project_name}/zones/{zone_name}/instances/{instance_name}`. | +| partial_uri | Same as `id` above. | +| self_link | The full resource URI representing this instance. Has the form `https://www.googleapis.com/compute/v1/{partial_uri}` | +| instancename | The name of the instance, e.g. "my-instance" | +| zone_name | The zone that the instance is installed on | +| hostname | If present, the hostname of the instance | +| exposed_internet | Set to True with `exposed_internet_type = 'direct'` if there is an 'allow' IPRule attached to one of the instance's ingress firewalls with the following conditions: The 'allow' IpRule allows traffic from one or more TCP ports, and the 'allow' IpRule is not superceded by a 'deny' IPRule (in GCP, a firewall rule of priority 1 gets applied ahead of a firewall rule of priority 100, and 'deny' rules of the same priority are applied ahead of 'allow' rules) | +| status | The [GCP Instance Lifecycle](https://cloud.google.com/compute/docs/instances/instance-life-cycle) state of the instance | +#### Relationships + +- GCPInstances are resources of GCPProjects. + + ``` + (GCPProject)-[RESOURCE]->(GCPInstance) + ``` + +- GCPNetworkInterfaces are attached to GCPInstances + + ``` + (GCPInstance)-[NETWORK_INTERFACE]->(GCPNetworkInterface) + ``` + +- GCP Instances may be members of one or more GCP VPCs. + + ``` + (GCPInstance)-[:MEMBER_OF_GCP_VPC]->(GCPVpc) + ``` + + Also note that this relationship is a shortcut for: + + ``` + (GCPInstance)-[:NETWORK_INTERFACE]->(:GCPNetworkInterface)-[:PART_OF_SUBNET]->(GCPSubnet)<-[:RESOURCE]-(GCPVpc) + ``` + +- GCP Instances may have GCP Tags defined on them for use in [network firewall routing](https://cloud.google.com/blog/products/gcp/labelling-and-grouping-your-google-cloud-platform-resources). + + ``` + (GCPInstance)-[:TAGGED]->(GCPNetworkTag) + ``` + +- GCP Firewalls allow ingress to GCP instances. + ``` + (GCPFirewall)-[:FIREWALL_INGRESS]->(GCPInstance) + ``` + + Note that this relationship is a shortcut for: + ``` + (vpc:GCPVpc)<-[MEMBER_OF_GCP_VPC]-(GCPInstance)-[TAGGED]->(GCPNetworkTag)-[TARGET_TAG]-(GCPFirewall{direction: 'INGRESS'})<-[RESOURCE]-(vpc) + ``` + + as well as + ``` + MATCH (fw:GCPFirewall{direction: 'INGRESS', has_target_service_accounts: False}}) + WHERE NOT (fw)-[TARGET_TAG]->(GCPNetworkTag) + MATCH (GCPInstance)-[MEMBER_OF_GCP_VPC]->(GCPVpc)-[RESOURCE]->(fw) + ``` + +### GCPNetworkTag + +Representation of a Tag defined on a GCP Instance or GCP Firewall. Tags are defined on GCP instances for use in [network firewall routing](https://cloud.google.com/blog/products/gcp/labelling-and-grouping-your-google-cloud-platform-resources). + +| Field | Description | +| ----------- | ---------------------------------------------------------------------------------------------------------- | +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | GCP doesn't define a resource URI for Tags so we define this as `{instance resource URI}/tags/{tag value}` | +| tag_id | same as `id` | +| value | The actual value of the tag | + +#### Relationships + +- GCP Instances can be labeled with tags. + ``` + (GCPInstance)-[:TAGGED]->(GCPNetworkTag) + ``` + +- GCP Firewalls can be labeled with tags to direct traffic to or deny traffic to labeled GCPInstances + ``` + (GCPFirewall)-[:TARGET_TAG]->(GCPNetworkTag) + ``` + +- GCPNetworkTags are defined on a VPC and only have effect on assets in that VPC + + ``` + (GCPVpc)-[DEFINED_IN]->(GCPNetworkTag) + ``` + +### GCPVpc + +Representation of a GCP [VPC](https://cloud.google.com/compute/docs/reference/rest/v1/networks/). In GCP documentation this is also known simply as a "Network" object. + +| Field | Description | +| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The partial resource URI representing this VPC. Has the form `projects/{project_name}/global/networks/{vpc name}`. | +| partial_uri | Same as `id` | +| self_link | The full resource URI representing this VPC. Has the form `https://www.googleapis.com/compute/v1/{partial_uri}` | +| name | The name of the VPC | +| project_id | The project ID that this VPC belongs to | +| auto_create_subnetworks | When set to true, the VPC network is created in "auto" mode. When set to false, the VPC network is created in "custom" mode. An auto mode VPC network starts with one subnet per region. Each subnet has a predetermined range as described in [Auto mode VPC network IP ranges](https://cloud.google.com/vpc/docs/vpc#ip-ranges). | +| routing_confg_routing_mode | The network-wide routing mode to use. If set to REGIONAL, this network's Cloud Routers will only advertise routes with subnets of this network in the same region as the router. If set to GLOBAL, this network's Cloud Routers will advertise routes with all subnets of this network, across regions. | +| description | A description for the VPC | + +#### Relationships + +- GCPVpcs are part of projects + + ``` + (GCPProject)-[RESOURCE]->(GCPVpc) + ``` + +- GCPVpcs contain GCPSubnets + + ``` + (GCPVpc)-[RESOURCE]->(GCPSubnet) + ``` + +- GCPSubnets are part of GCP VPCs + + ``` + (GCPVpc)-[RESOURCE]->(GCPSubnet) + ``` + +- GCPNetworkTags are defined on a VPC and only have effect on assets in that VPC + + ``` + (GCPVpc)-[DEFINED_IN]->(GCPNetworkTag) + ``` + +- GCP Instances may be members of one or more GCP VPCs. + + ``` + (GCPInstance)-[:MEMBER_OF_GCP_VPC]->(GCPVpc) + ``` + + Also note that this relationship is a shortcut for: + + ``` + (GCPInstance)-[:NETWORK_INTERFACE]->(:GCPNetworkInterface)-[:PART_OF_SUBNET]->(GCPSubnet)<-[:RESOURCE]-(GCPVpc) + ``` + +### GCPNetworkInterface + +Representation of a GCP Instance's [network interface](https://cloud.google.com/compute/docs/reference/rest/v1/instances/list) (scroll down to the fields on "networkInterface"). + +| Field | Description | +| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | A partial resource URI representing this network interface. Note: GCP does not define a partial resource URI for network interfaces, so we create one so we can uniquely identify GCP network interfaces. Has the form `projects/{project_name}/zones/{zone_name}/instances/{instance_name}/networkinterfaces/{network interface name}`. | +| nic_id | Same as `id` | +| name | The name of the network interface | +| private_ip | The private IP address of this network interface. This IP is valid on the network interface's VPC. | + +#### Relationships + +- GCPNetworkInterfaces are attached to GCPInstances + + ``` + (GCPInstance)-[NETWORK_INTERFACE]->(GCPNetworkInterface) + ``` + +- GCPNetworkInterfaces are connected to GCPSubnets + + ``` + (GCPNetworkInterface)-[PART_OF_SUBNET]->(GCPSubnet) + ``` + +- GCPNetworkInterfaces have GCPNicAccessConfig objects defined on them + + ``` + (GCPNetworkInterface)-[RESOURCE]->(GCPNicAccessConfig) + ``` + + +### GCPNicAccessConfig + +Representation of the AccessConfig object on a GCP Instance's [network interface](https://cloud.google.com/compute/docs/reference/rest/v1/instances/list) (scroll down to the fields on "networkInterface"). + +| Field | Description | +| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | A partial resource URI representing this AccessConfig. Note: GCP does not define a partial resource URI for AccessConfigs, so we create one so we can uniquely identify GCP network interface access configs. Has the form `projects/{project_name}/zones/{zone_name}/instances/{instance_name}/networkinterfaces/{network interface name}/accessconfigs/{access config type}`. | +| partial_uri | Same as `id` | +| type | The type of configuration. GCP docs say: "The default and only option is ONE_TO_ONE_NAT." | +| name | The name of this access configuration. The default and recommended name is External NAT, but you can use any arbitrary string, such as My external IP or Network Access. | +| public_ip | The external IP associated with this instance | +| set_public_ptr | Specifies whether a public DNS 'PTR' record should be created to map the external IP address of the instance to a DNS domain name. | +| public_ptr_domain_name | The DNS domain name for the public PTR record. You can set this field only if the setPublicPtr field is enabled. | +| network_tier | This signifies the networking tier used for configuring this access configuration and can only take the following values: PREMIUM, STANDARD. | + +#### Relationships + +- GCPNetworkInterfaces have GCPNicAccessConfig objects defined on them + + ``` + (GCPNetworkInterface)-[RESOURCE]->(GCPNicAccessConfig) + ``` + + +### GCPRecordSet + +Representation of a GCP [Resource Record Set](https://cloud.google.com/dns/docs/reference/v1/). + +| Field | Description | +| ---------- | ------------------------------------------------------- | +| data | Data contained in the record +| firstseen | Timestamp of when a sync job first discovered this node | +| **id** |Same as `name`| +| name | The name of the Resource Record Set | +| type | The identifier of a supported record type. See the list of [Supported DNS record types](https://cloud.google.om/dns/docs/overview#supported_dns_record_types). +| ttl | Number of seconds that this ResourceRecordSet can be cached by resolvers. + + +#### Relationships + +- GCPRecordSets are records of GCPDNSZones. + + ``` + (GCPDNSZone)-[HAS_RECORD]->(GCPRecordSet) + ``` + + +### GCPSubnet + +Representation of a GCP [Subnetwork](https://cloud.google.com/compute/docs/reference/rest/v1/subnetworks). + +| Field | Description | +| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | A partial resource URI representing this Subnet. Has the form `projects/{project}/regions/{region}/subnetworks/{subnet name}`. | +| partial_uri | Same as `id` | +| self_link | The full resource URI representing this subnet. Has the form `https://www.googleapis.com/compute/v1/{partial_uri}` | +| project_id | The project ID that this Subnet belongs to | +| name | The name of this Subnet | +| region | The region of this Subnet | +| gateway_address | Gateway IP address of this Subnet | +| ip_cidr_range | The CIDR range covered by this Subnet | +| vpc_partial_uri | The partial URI of the VPC that this Subnet is a part of | +| private_ip_google_access | Whether the VMs in this subnet can access Google services without assigned external IP addresses. This field can be both set at resource creation time and updated using setPrivateIpGoogleAccess. | + +#### Relationships + +- GCPSubnets are part of GCP VPCs + + ``` + (GCPVpc)-[RESOURCE]->(GCPSubnet) + ``` + +- GCPNetworkInterfaces are connected to GCPSubnets + + ``` + (GCPNetworkInterface)-[PART_OF_SUBNET]->(GCPSubnet) + ``` + + +### GCPFirewall + +Representation of a GCP [Firewall](https://cloud.google.com/compute/docs/reference/rest/v1/firewalls/list). + +| Field | Description | +| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | A partial resource URI representing this Firewall. | +| partial_uri | Same as `id` | +| direction | Either 'INGRESS' for inbound or 'EGRESS' for outbound | +| disabled | Whether this firewall object is disabled | +| priority | The priority of this firewall rule from 1 (apply this first)-65535 (apply this last) | +| self_link | The full resource URI to this firewall | +| has_target_service_accounts | Set to True if this Firewall has target service accounts defined. This field is currently a placeholder for future functionality to add GCP IAM objects to Cartography. If True, this firewall rule will only apply to GCP instances that use the specified target service account. | + +#### Relationships + +- Firewalls belong to VPCs + + ``` + (GCPVpc)-[RESOURCE]->(GCPFirewall) + ``` + +- Firewalls define rules that allow traffic + + ``` + (GcpIpRule)-[ALLOWED_BY]->(GCPFirewall) + ``` + +- Firewalls define rules that deny traffic + + ``` + (GcpIpRule)-[DENIED_BY]->(GCPFirewall) + ``` + +- GCP Firewalls can be labeled with tags to direct traffic to or deny traffic to labeled GCPInstances + ``` + (GCPFirewall)-[:TARGET_TAG]->(GCPNetworkTag) + ``` + +- GCP Firewalls allow ingress to GCP instances. + ``` + (GCPFirewall)-[:FIREWALL_INGRESS]->(GCPInstance) + ``` + + Note that this relationship is a shortcut for: + ``` + (vpc:GCPVpc)<-[MEMBER_OF_GCP_VPC]-(GCPInstance)-[TAGGED]->(GCPNetworkTag)-[TARGET_TAG]-(GCPFirewall{direction: 'INGRESS'})<-[RESOURCE]-(vpc) + ``` + + as well as + ``` + MATCH (fw:GCPFirewall{direction: 'INGRESS', has_target_service_accounts: False}}) + WHERE NOT (fw)-[TARGET_TAG]->(GCPNetworkTag) + MATCH (GCPInstance)-[MEMBER_OF_GCP_VPC]->(GCPVpc)-[RESOURCE]->(fw) + ``` + + +### GCPForwardingRule + +Representation of GCP [Forwarding Rules](https://cloud.google.com/compute/docs/reference/rest/v1/forwardingRules/list) and [Global Forwarding Rules](https://cloud.google.com/compute/docs/reference/rest/v1/globalForwardingRules/list). + +| Field | Description | +| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | A partial resource URI representing this Forwarding Rule | +| partial_uri | Same as `id` | +| ip_address | IP address that this Forwarding Rule serves | +| ip_protocol | IP protocol to which this rule applies | +| load_balancing_scheme | Specifies the Forwarding Rule type | +| name | Name of the Forwarding Rule | +| network | A partial resource URI of the network this Forwarding Rule belongs to | +| port_range | Port range used in conjunction with a target resource. Only packets addressed to ports in the specified range will be forwarded to target configured | +| ports | Ports to forward to a backend service. Only packets addressed to these ports are forwarded to the backend services configured | +| project_id | The project ID that this Forwarding Rule belongs to | +| region | The region of this Forwarding Rule | +| self_link | Server-defined URL for the resource | +| subnetwork | A partial resource URI of the subnetwork this Forwarding Rule belongs to | +| target | A partial resource URI of the target resource to receive the traffic | + +#### Relationships + +- GCPForwardingRules can be a resource of a GCPVpc. + + ``` + (GCPVpc)-[RESOURCE]->(GCPForwardingRule) + ``` + +- GCPForwardingRules can be a resource of a GCPSubnet. + + ``` + (GCPSubnet)-[RESOURCE]->(GCPForwardingRule) + ``` + +### GKECluster + +Representation of a GCP [GKE Cluster](https://cloud.google.com/kubernetes-engine/docs/reference/rest/v1/). + +| Field | Description | +| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| basic_auth | Set to `True` if both `masterauth_username` and `masterauth_password` are set | +| created_at | The date and time the cluster was created | +| cluster_ipv4cidr | The IP address range of the container pods in the cluster | +| current_master_version | The current software version of the master endpoint | +| database_encryption | Configuration of etcd encryption | +| description | An optional description of the cluster | +| endpoint | The IP address of the cluster's master endpoint. The endpoint can be accessed from the internet at https://username:password@endpoint/ | +| exposed_internet | Set to `True` if at least among `private_nodes`, `private_endpoint_enabled`, or `master_authorized_networks` are disabled | +| firstseen | Timestamp of when a sync job first discovered this node | +| **id** | Same as `self_link` | +| initial_version | The initial Kubernetes version for the cluster | +| location | The name of the Google Compute Engine zone or region in which the cluster resides | +| logging_service | The logging service used to write logs. Available options: `logging.googleapis.com/kubernetes`, `logging.googleapis.com`, `none` | +| master_authorized_networks | If enabled, it disallows all external traffic to access Kubernetes master through HTTPS except traffic from the given CIDR blocks, Google Compute Engine Public IPs and Google Prod IPs | +| masterauth_username | The username to use for HTTP basic authentication to the master endpoint. For clusters v1.6.0 and later, basic authentication can be disabled by leaving username unspecified (or setting it to the empty string) | +| masterauth_password | The password to use for HTTP basic authentication to the master endpoint. If a password is provided for cluster creation, username must be non-empty | +| monitoring_service | The monitoring service used to write metrics. Available options: `monitoring.googleapis.com/kubernetes`, `monitoring.googleapis.com`, `none` | +| name | The name of the cluster | +| network | The name of the Google Compute Engine network to which the cluster is connected | +| network_policy | Set to `True` if a network policy provider has been enabled | +| private_endpoint_enabled | Whether the master's internal IP address is used as the cluster endpoint | +| private_endpoint | The internal IP address of the cluster's master endpoint | +| private_nodes | If enabled, all nodes are given only private addresses and communicate with the master via private networking | +| public_endpoint | The external IP address of the cluster's master endpoint | +| **self_link** | Server-defined URL for the resource | +| services_ipv4cidr | The IP address range of the Kubernetes services in the cluster | +| shielded_nodes | Whether Shielded Nodes are enabled | +| status | The current status of the cluster | +| subnetwork | The name of the Google Compute Engine subnetwork to which the cluster is connected | +| zone | The name of the Google Compute Engine zone in which the cluster resides | + + +#### Relationships + +- GKEClusters are resources of GCPProjects. + + ``` + (GCPProject)-[RESOURCE]->(GKECluster) + ``` + + +### IpRule::IpPermissionInbound::GCPIpRule + +An IpPermissionInbound node is a specific type of IpRule. It represents a generic inbound IP-based rules. The creation of this node is currently derived from ingesting AWS [EC2 Security Group](#ec2securitygroup) rules. + +| Field | Description | +| ----------- | ----------------------------------------------------------- | +| **ruleid** | `{firewall_partial_uri}/{rule_type}/{port_range}{protocol}` | +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| protocol | The protocol this rule applies to | +| fromport | Lowest port in the range defined by this rule | +| toport | Highest port in the range defined by this rule | + +#### Relationships + +- GCP Firewall rules are defined on IpRange objects. + + ``` + (GCPIpRule, IpRule, IpPermissionInbound)<-[MEMBER_OF_IP_RULE)-(:IpRange) + ``` + +- Firewalls define rules that allow traffic + + ``` + (GcpIpRule)-[ALLOWED_BY]->(GCPFirewall) + ``` + +- Firewalls define rules that deny traffic + + ``` + (GcpIpRule)-[DENIED_BY]->(GCPFirewall) + ``` + +### IpRange + +Representation of an IP range or subnet. + +| Field | Description | +| ----------- | ------------------------------------------------------------------------ | +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | CIDR notation for the IP range. E.g. "0.0.0.0/0" for the whole internet. | + +#### Relationships + +- GCP Firewall rules are defined on IpRange objects. + + ``` + (GCPIpRule, IpRule, IpPermissionInbound)<-[MEMBER_OF_IP_RULE)-(:IpRange) + ``` diff --git a/_sources/modules/github/config.md.txt b/_sources/modules/github/config.md.txt new file mode 100644 index 0000000000..c5f5fbca5e --- /dev/null +++ b/_sources/modules/github/config.md.txt @@ -0,0 +1,37 @@ +## Github Configuration + +.. _github_config: + +Follow these steps to analyze GitHub repos and other objects with Cartography. + +1. Prepare your GitHub credentials. + 1. Prepare a GitHub token; the following scopes are required, at minimum: `repo`, `read:org`, `read:user`, `user:email` + 1. GitHub ingest supports multiple endpoints, such as a public instance and an enterprise instance by taking a base64-encoded config object structured as + ```json + { + "organization": [ + { + "token": "faketoken", + "url": "https://api.github.com/graphql", + "name": "fakeorg" + }, + { + "token": "stillfake", + "url": "https://github.example.com/api/graphql", + "name": "fakeorg" + }] + } + ``` + 1. For each GitHub instance you want to ingest, generate an API token as documented in the [API reference](https://developer.github.com/v3/auth/) + 1. Create your auth config as shown above using the token obtained in the previous step. If you are configuring only the public GitHub instance, you can just use the first config block and delete the second. The name field is for the organization name you want to ingest. + 1. Base64 encode the auth object. You can encode the above sample in Python using + ```python + import json + import base64 + auth_json = json.dumps({"organization":[{"token":"faketoken","url":"https://api.github.com/graphql","name":"fakeorg"},{"token":"stillfake","url":"https://github.example.com/api/graphql","name":"fakeorg"}]}) + base64.b64encode(auth_json.encode()) + ``` + and the resulting environment variable would be ```eyJvcmdhbml6YXRpb24iOiBbeyJ0b2tlbiI6ICJmYWtldG9rZW4iLCAidXJsIjogImh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vZ3JhcGhxbCIsICJuYW1lIjogImZha2VvcmcifSwgeyJ0b2tlbiI6ICJzdGlsbGZha2UiLCAidXJsIjogImh0dHBzOi8vZ2l0aHViLmV4YW1wbGUuY29tL2FwaS9ncmFwaHFsIiwgIm5hbWUiOiAiZmFrZW9yZyJ9XX0=``` +1. Populate an environment variable of your choice with the contents of the base64 output from the previous step. +1. Call the `cartography` CLI with `--github-config-env-var YOUR_ENV_VAR_HERE`. +1. `cartography` will then load your graph with data from all the organizations you specified. diff --git a/_sources/modules/github/index.rst.txt b/_sources/modules/github/index.rst.txt new file mode 100644 index 0000000000..0bfc35ef1e --- /dev/null +++ b/_sources/modules/github/index.rst.txt @@ -0,0 +1,14 @@ +Github +###### + +The github module has the following coverage: + +* Repos +* Branches +* Users + +.. toctree:: + :hidden: + :glob: + + * diff --git a/_sources/modules/github/schema.md.txt b/_sources/modules/github/schema.md.txt new file mode 100644 index 0000000000..e1eb5d5c95 --- /dev/null +++ b/_sources/modules/github/schema.md.txt @@ -0,0 +1,218 @@ +## Github Schema + +.. _github_schema: + +### GitHubRepository + +Representation of a single GitHubRepository (repo) [repository object](https://developer.github.com/v4/object/repository/). This node contains all data unique to the repo. + + +| Field | Description | +|-------|--------------| +| firstseen| Timestamp of when a sync job first created this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The GitHub repo id. These are not unique across GitHub instances, so are prepended with the API URL the id applies to | +| createdat | GitHub timestamp from when the repo was created | +| name | Name of the repo | +| fullname | Name of the organization and repo together | +| description | Text describing the repo | +| primarylanguage | The primary language used in the repo | +| homepage | The website used as a homepage for project information | +| defaultbranch | The default branch used by the repo, typically master | +| defaultbranchid | The unique identifier of the default branch | +| private | True if repo is private | +| disabled | True if repo is disabled | +| archived | True if repo is archived | +| locked | True if repo is locked | +| giturl | URL used to access the repo from git commandline | +| url | Web URL for viewing the repo +| sshurl | URL for access the repo via SSH +| updatedat | GitHub timestamp for last time repo was modified | + + +#### Relationships + +- GitHubUsers or GitHubOrganizations own GitHubRepositories. + + ``` + (GitHubUser)-[OWNER]->(GitHubRepository) + (GitHubOrganization)-[OWNER]->(GitHubRepository) + ``` + +- GitHubRepositories in an organization can have outside collaborators with different permissions, including ADMIN, +WRITE, MAINTAIN, TRIAGE, and READ ([Reference](https://docs.github.com/en/graphql/reference/enums#repositorypermission)). + + ``` + (GitHubUser)-[:OUTSIDE_COLLAB_{ACTION}]->(GitHubRepository) + ``` + +- GitHubRepositories use ProgrammingLanguages + ``` + (GitHubRepository)-[:LANGUAGE]->(ProgrammingLanguage) + ``` +- GitHubRepositories have GitHubBranches + ``` + (GitHubRepository)-[:BRANCH]->(GitHubBranch) + ``` +- GitHubTeams can have various levels of [access](https://docs.github.com/en/graphql/reference/enums#repositorypermission) to GitHubRepositories. + + ``` + (GitHubTeam)-[ADMIN|READ|WRITE|TRIAGE|MAINTAIN]->(GitHubRepository) + ``` + +### GitHubOrganization + +Representation of a single GitHubOrganization [organization object](https://developer.github.com/v4/object/organization/). This node contains minimal data for the GitHub Organization. + + +| Field | Description | +|-------|--------------| +| firstseen| Timestamp of when a sync job first created this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The URL of the GitHub organization | +| username | Name of the organization | + + +#### Relationships + +- GitHubOrganizations own GitHubRepositories. + + ``` + (GitHubOrganization)-[OWNER]->(GitHubRepository) + ``` + +- GitHubTeams are resources under GitHubOrganizations + + ``` + (GitHubOrganization)-[RESOURCE]->(GitHubTeam) + ``` + + +### GitHubTeam + +A GitHubTeam [organization object](https://docs.github.com/en/graphql/reference/objects#team). + + +| Field | Description | +|-------|--------------| +| firstseen| Timestamp of when a sync job first created this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The URL of the GitHub Team | +| name | The name (a.k.a URL slug) of the GitHub Team | +| description | Description of the GitHub team | + + +#### Relationships + +- GitHubTeams can have various levels of [access](https://docs.github.com/en/graphql/reference/enums#repositorypermission) to GitHubRepositories. + + ``` + (GitHubTeam)-[ADMIN|READ|WRITE|TRIAGE|MAINTAIN]->(GitHubRepository) + ``` + +- GitHubTeams are resources under GitHubOrganizations + + ``` + (GitHubOrganization)-[RESOURCE]->(GitHubTeam) + ``` + +### GitHubUser + +Representation of a single GitHubUser [user object](https://developer.github.com/v4/object/user/). This node contains minimal data for the GitHub User. + + +| Field | Description | +|-------|--------------| +| firstseen| Timestamp of when a sync job first created this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The URL of the GitHub user | +| username | Name of the user | +| fullname | The full name | +| has_2fa_enabled | Whether the user has 2-factor authentication enabled | +| role | Either 'ADMIN' (denoting that the user is an owner of a Github organization) or 'MEMBER' | +| is_site_admin | Whether the user is a site admin | +| permission | Only present if the user is an [outside collaborator](https://docs.github.com/en/graphql/reference/objects#repositorycollaboratorconnection) of this repo. +`permission` is either ADMIN, MAINTAIN, READ, TRIAGE, or WRITE ([ref](https://docs.github.com/en/graphql/reference/enums#repositorypermission)). +| email | The user's publicly visible profile email. +| company | The user's public profile company. + + +#### Relationships + +- GitHubUsers own GitHubRepositories. + + ``` + (GitHubUser)-[OWNER]->(GitHubRepository) + ``` + +- GitHubRepositories in an organization can have outside collaborators with different permissions, including ADMIN, +WRITE, MAINTAIN, TRIAGE, and READ ([Reference](https://docs.github.com/en/graphql/reference/enums#repositorypermission)). + + ``` + (GitHubUser)-[:OUTSIDE_COLLAB_{ACTION}]->(GitHubRepository) + ``` + +### GitHubBranch + +Representation of a single GitHubBranch [ref object](https://developer.github.com/v4/object/ref). This node contains minimal data for a repository branch. + + +| Field | Description | +|-------|--------------| +| firstseen| Timestamp of when a sync job first created this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The GitHub branch id. These are not unique across GitHub instances, so are prepended with the API URL the id applies to | +| name | Name of the branch | + + +#### Relationships + +- GitHubRepositories have GitHubBranches. + + ``` + (GitHubBranch)<-[BRANCH]-(GitHubRepository) + ``` + +### ProgrammingLanguage + +Representation of a single Programming Language [language object](https://developer.github.com/v4/object/language). This node contains programming language information. + + +| Field | Description | +|-------|--------------| +| firstseen| Timestamp of when a sync job first created this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | Language ids need not be tracked across instances, so defaults to the name | +| name | Name of the language | + + +#### Relationships + +- GitHubRepositories use ProgrammingLanguages. + + ``` + (ProgrammingLanguage)<-[LANGUAGE]-(GitHubRepository) + ``` + + +### Dependency::PythonLibrary + +Representation of a Python library as listed in a [requirements.txt](https://pip.pypa.io/en/stable/user_guide/#requirements-files) +or [setup.cfg](https://setuptools.pypa.io/en/latest/userguide/declarative_config.html) file. +Within a setup.cfg file, cartography will load everything from `install_requires`, `setup_requires`, and `extras_require`. + +| Field | Description | +|-------|-------------| +|**id**|The [canonicalized](https://packaging.pypa.io/en/latest/utils/#packaging.utils.canonicalize_name) name of the library. If the library was pinned in a requirements file using the `==` operator, then `id` has the form ``{canonical name}\|{pinned_version}``.| +|name|The [canonicalized](https://packaging.pypa.io/en/latest/utils/#packaging.utils.canonicalize_name) name of the library.| +|version|The exact version of the library. This field is only present if the library was pinned in a requirements file using the `==` operator.| + +#### Relationships + +- Software on Github repos can import Python libraries by optionally specifying a version number. + + ``` + (GitHubRepository)-[:REQUIRES{specifier}]->(PythonLibrary) + ``` + + - specifier: A string describing this library's version e.g. "<4.0,>=3.0" or "==1.0.2". This field is only present on the `:REQUIRES` edge if the repo's requirements file provided a version pin. diff --git a/_sources/modules/gsuite/config.md.txt b/_sources/modules/gsuite/config.md.txt new file mode 100644 index 0000000000..d726405ba7 --- /dev/null +++ b/_sources/modules/gsuite/config.md.txt @@ -0,0 +1,93 @@ +## GSuite Configuration + +.. _gsuite_config: + +This module allows authentication from a service account or via OAuth tokens. + +Method 1: Using service account (legacy) + +Ingesting GSuite Users and Groups utilizes the [Google Admin SDK](https://developers.google.com/admin-sdk/). + +1. [Enable Google API access](https://support.google.com/a/answer/60757?hl=en) +1. Create a new G Suite user account and accept the Terms of Service. This account will be used as the domain-wide delegated access. +1. [Perform G Suite Domain-Wide Delegation of Authority](https://developers.google.com/admin-sdk/directory/v1/guides/delegation) +1. Download the service account's credentials +1. Export the environmental variables: + 1. `GSUITE_GOOGLE_APPLICATION_CREDENTIALS` - location of the credentials file. + 1. `GSUITE_DELEGATED_ADMIN` - email address that you created in step 2 + +## Method 2: Using OAuth + +1. Create an App on [Google Cloud Console](https://console.cloud.google.com/) +1. Refer to follow documentation if needed: + 1. https://developers.google.com/admin-sdk/directory/v1/quickstart/python + 1. https://developers.google.com/workspace/guides/get-started + 1. https://support.google.com/a/answer/7281227?hl=fr +1. Download credentials file +1. Use helper script below for OAuth flow to obtain refresh_token +1. Serialize needed secret + ```python + import json + import base64 + auth_json = json.dumps({"client_id":"xxxxx.apps.googleusercontent.com","client_secret":"ChangeMe", "refresh_token":"ChangeMe", "token_uri": "https://oauth2.googleapis.com/token"}) + base64.b64encode(auth_json.encode()) + ``` +1. Populate an environment variable of your choice with the contents of the base64 output from the previous step. +1. Call the `cartography` CLI with `--gsuite-tokens-env-var YOUR_ENV_VAR_HERE` and `--gsuite-auth-method oauth`. + + + + +Google Oauth Helper : +```python +from __future__ import print_function +import json +import os + +from google_auth_oauthlib.flow import InstalledAppFlow +from googleapiclient.discovery import build + + +scopes = ["https://www.googleapis.com/auth/admin.directory.userreadonly", "https://www.googleapis.com/auth/admin.directory.group.readonly", "https://www.googleapis.com/auth/admin.directory.group.member"] + +print('Go to https://console.cloud.google.com/ > API & Services > Credentials and download secrets') +project_id = input('Provide your project ID:') +client_id = input('Provide your client ID:') +client_secret = input('Provide your client secret:') +with open('credentials.json', 'w', encoding='utf-8') as fc: + data = { + "installed": { + "client_id": client_id, + "project_id": project_id, + "auth_uri":"https://accounts.google.com/o/oauth2/auth", + "token_uri":"https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs", + "client_secret":"client_secret", + "redirect_uris":["http://localhost"] + }} + json.dump(data, fc) +flow = InstalledAppFlow.from_client_secrets_file( + 'credentials.json', scopes) +flow.redirect_uri = 'http://localhost' +auth_url, _ = flow.authorization_url(prompt='consent') +print(f'Please go to this URL: {auth_url}') +code = input('Enter the authorization code: ') +flow.fetch_token(code=code) +creds = flow.credentials +print('Testing your credentials by gettings first 10 users in the domain ...') +service = build('admin', 'directory_v1', credentials=creds) +print('Getting the first 10 users in the domain') +results = service.users().list(customer='my_customer', maxResults=10, + orderBy='email').execute() +users = results.get('users', []) +if not users: + print('No users in the domain.') +else: + print('Users:') + for user in users: + print(u'{0} ({1})'.format(user['primaryEmail'], + user['name']['fullName'])) +print('Your credentials:') +print(json.dumps(creds.to_json(), indent=2)) +os.remove('credentials.json') +``` diff --git a/_sources/modules/gsuite/index.rst.txt b/_sources/modules/gsuite/index.rst.txt new file mode 100644 index 0000000000..a8818f2393 --- /dev/null +++ b/_sources/modules/gsuite/index.rst.txt @@ -0,0 +1,13 @@ +Google GSuite +############# + +The gsuite module has the following coverage: + +* Users +* Groups + +.. toctree:: + :hidden: + :glob: + + * diff --git a/_sources/modules/gsuite/schema.md.txt b/_sources/modules/gsuite/schema.md.txt new file mode 100644 index 0000000000..75e77c723b --- /dev/null +++ b/_sources/modules/gsuite/schema.md.txt @@ -0,0 +1,62 @@ +## GSuite Schema + +.. _gsuite_schema: + +### GSuiteUser + +Reference: +https://developers.google.com/admin-sdk/directory/v1/reference/users#resource + +| Field | Description | +|-------|--------------| +| id | The unique ID for the user as a string. A user id can be used as a user request URI's userKey +| user_id | duplicate of id. +| agreed_to_terms | This property is true if the user has completed an initial login and accepted the Terms of Service agreement. +| change_password_at_next_login | Indicates if the user is forced to change their password at next login. This setting doesn't apply when the user signs in via a third-party identity provider. +| creation_time | The time the user's account was created. The value is in ISO 8601 date and time format. The time is the complete date plus hours, minutes, and seconds in the form YYYY-MM-DDThh:mm:ssTZD. For example, 2010-04-05T17:30:04+01:00. +| customer_id | The customer ID to retrieve all account users. You can use the alias my_customer to represent your account's customerId. As a reseller administrator, you can use the resold customer account's customerId. To get a customerId, use the account's primary domain in the domain parameter of a users.list request. +| etag | ETag of the resource +| include_in_global_address_list | Indicates if the user's profile is visible in the G Suite global address list when the contact sharing feature is enabled for the domain. For more information about excluding user profiles, see the administration help center. +| ip_whitelisted | If true, the user's IP address is white listed. +| is_admin | Indicates a user with super admininistrator privileges. The isAdmin property can only be edited in the Make a user an administrator operation (makeAdmin method). If edited in the user insert or update methods, the edit is ignored by the API service. +| is_delegated_admin | Indicates if the user is a delegated administrator. Delegated administrators are supported by the API but cannot create or undelete users, or make users administrators. These requests are ignored by the API service. Roles and privileges for administrators are assigned using the Admin console. +| is_enforced_in_2_sv | Is 2-step verification enforced (Read-only) +| is_enrolled_in_2_sv | Is enrolled in 2-step verification (Read-only) +| is_mailbox_setup | Indicates if the user's Google mailbox is created. This property is only applicable if the user has been assigned a Gmail license. +| kind | The type of the API resource. For Users resources, the value is admin#directory#user. +| last_login_time | The last time the user logged into the user's account. The value is in ISO 8601 date and time format. The time is the complete date plus hours, minutes, and seconds in the form YYYY-MM-DDThh:mm:ssTZD. For example, 2010-04-05T17:30:04+01:00. +| name | First name + Last name +| family_name | The user's last name. Required when creating a user account. +| given_name | The user's first name. Required when creating a user account. +| org_unit_path | The full path of the parent organization associated with the user. If the parent organization is the top-level, it is represented as a forward slash (/). +| primary_email | The user's primary email address. This property is required in a request to create a user account. The primaryEmail must be unique and cannot be an alias of another user. +| suspended | Indicates if user is suspended +| thumbnail_photo_etag | ETag of the user's photo +| thumbnail_photo_url | Photo Url of the user +| lastupdated | Timestamp of when a sync job last updated this node +| firstseen | Timestamp of when a sync job first discovered this node + +#### Relationships +- GSuiteUser is an identity for a Human + ``` + (Human)-[IDENTITY_GSUITE]->(GSuiteUser) + ``` + +### GSuiteGroup + +Reference: +https://developers.google.com/admin-sdk/directory/v1/reference/groups + + +| Field | Description | +|-------|--------------| +| id | The unique ID of a group. A group id can be used as a group request URI's groupKey. +| admin_created | Value is true if this group was created by an administrator rather than a user. +| description | An extended description to help users determine the purpose of a group. For example, you can include information about who should join the group, the types of messages to send to the group, links to FAQs about the group, or related groups. Maximum length is 4,096 characters. +| direct_members_count | The number of users that are direct members of the group. If a group is a member (child) of this group (the parent), members of the child group are not counted in the directMembersCount property of the parent group +| email | The group's email address. If your account has multiple domains, select the appropriate domain for the email address. The email must be unique. This property is required when creating a group. Group email addresses are subject to the same character usage rules as usernames, see the administration help center for the details. +| etag | ETag of the resource +| kind | The type of the API resource. For Groups resources, the value is admin#directory#group. +| name | The group's display name. +| lastupdated | Timestamp of when a sync job last updated this node +| firstseen | Timestamp of when a sync job first discovered this node diff --git a/_sources/modules/index.rst.txt b/_sources/modules/index.rst.txt new file mode 100644 index 0000000000..947aa7f149 --- /dev/null +++ b/_sources/modules/index.rst.txt @@ -0,0 +1,5 @@ +.. toctree:: + :hidden: + :glob: + + */index diff --git a/_sources/modules/jamf/index.rst.txt b/_sources/modules/jamf/index.rst.txt new file mode 100644 index 0000000000..0a24c9de2a --- /dev/null +++ b/_sources/modules/jamf/index.rst.txt @@ -0,0 +1,7 @@ +Jamf +#### + +.. toctree:: + :glob: + + * diff --git a/_sources/modules/jamf/schema.md.txt b/_sources/modules/jamf/schema.md.txt new file mode 100644 index 0000000000..362bb9d647 --- /dev/null +++ b/_sources/modules/jamf/schema.md.txt @@ -0,0 +1,17 @@ +## Jamf Schema + +.. _jamf_schema: + +### JamfComputerGroup + +Representation of a Jamf computer group. + +| Field | Description | +|-------|-------------| +|id|The group id| +|name|The friendly name of the group| +|is_smart| Whether the group is [smart](https://docs.jamf.com/10.4.0/jamf-pro/administrator-guide/Smart_Computer_Groups.html)| + +#### Relationships + +- Coming soon! diff --git a/_sources/modules/kubernetes/config.md.txt b/_sources/modules/kubernetes/config.md.txt new file mode 100644 index 0000000000..f6b2b5047d --- /dev/null +++ b/_sources/modules/kubernetes/config.md.txt @@ -0,0 +1,9 @@ +## Kubernetes Configuration + +.. _kubernetes_config: + +Follow these steps to analyze Kubernetes objects in Cartography. + +1. Configure a [kubeconfig file](https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/) specifying access to one or mulitple clusters. + - Access to mutliple K8 clusters can be organized in a single kubeconfig file. Intel module of Kubernetes will automatically detect that and attempt to sync each cluster. +2. Note down the path of configured kubeconfig file and pass it to cartography CLI with `--k8s-kubeconfig` parameter. diff --git a/_sources/modules/kubernetes/index.rst.txt b/_sources/modules/kubernetes/index.rst.txt new file mode 100644 index 0000000000..fed3b0607c --- /dev/null +++ b/_sources/modules/kubernetes/index.rst.txt @@ -0,0 +1,17 @@ +Kubernetes +########## + +The kubernetes module has the following coverage: + +* Cluster +* Namespace +* Secret +* Service +* Pod +* Container + +.. toctree:: + :hidden: + :glob: + + * diff --git a/_sources/modules/kubernetes/schema.md.txt b/_sources/modules/kubernetes/schema.md.txt new file mode 100644 index 0000000000..75018858d4 --- /dev/null +++ b/_sources/modules/kubernetes/schema.md.txt @@ -0,0 +1,134 @@ +## Kubernetes Schema + +.. _kubernetes_schema: + +### KubernetesCluster +Representation of a [Kubernetes Cluster.](https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/) + +| Field | Description | +|-------|-------------| +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | Identifier for the cluster i.e. UID of `kube-system` namespace | +| name | Name assigned to the cluster which is derived from kubeconfig context | + +#### Relationships +- KubernetesCluster has KubernetesNamespaces. + ``` + (KubernetesCluster)-[HAS_NAMESPACE]->(KubernetesNamespace) + ``` + +- KubernetesCluster can have KubernetesPods. + ``` + (KubernetesCluster)-[HAS_POD]->(KubernetesPod) + ``` + +### KubernetesNamespace +Representation of a [Kubernetes Namespace.](https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/) + +| Field | Description | +|-------|-------------| +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | UID of the kubernetes namespace | +| name | Name of the kubernetes namespace | +| created\_at | Timestamp of the creation time of the kubernetes namespace | +| deleted\_at | Timestamp of the deletion time of the kubernetes namespace | + +#### Relationships +- KubernetesNamespace can have KubernetesPods. + ``` + (KubernetesNamespace)-[HAS_POD]->(KubernetesPod) + ``` + +- KubernetesNamespace can have KubernetesServices. + ``` + (KubernetesNamespace)-[HAS_SERVICE]->(KubernetesService) + ``` + +- KubernetesNamespace can have KubernetesSecrets. + ``` + (KubernetesNamespace)-[HAS_SECRET]->(KubernetesSecret) + ``` + +### KubernetesPod +Representation of a [Kubernetes Pod.](https://kubernetes.io/docs/concepts/workloads/pods/) + +| Field | Description | +|-------|-------------| +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | UID of the kubernetes pod | +| name | Name of the kubernetes pod | +| status\_phase | The phase of a Pod is a simple, high-level summary of where the Pod is in its lifecycle. | +| created\_at | Timestamp of the creation time of the kubernetes pod | +| deleted\_at | Timestamp of the deletion time of the kubernetes pod | + +#### Relationships +- KubernetesPod has KubernetesContainers. + ``` + (KubernetesPod)-[HAS_CONTAINER]->(KubernetesContainer) + ``` + +### KubernetesContainer +Representation of a [Kubernetes Container.](https://kubernetes.io/docs/concepts/workloads/pods/#how-pods-manage-multiple-containers) + +| Field | Description | +|-------|-------------| +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | Identifier for the container which is derived from the UID of pod and the name of container | +| name | Name of the container in kubernetes pod | +| image | Docker image used in the container | +| status\_image\_id | ImageID of the container's image. | +| status\_image\_sha | The SHA portion of the status\_image\_id | +| status\_ready | Specifies whether the container has passed its readiness probe. | +| status\_started | Specifies whether the container has passed its startup probe. | +| statys\_state | State of the container (running, terminated, waiting) | + +#### Relationships +- KubernetesPod has KubernetesContainers. + ``` + (KubernetesPod)-[HAS_CONTAINER]->(KubernetesContainer) + ``` + +### KubernetesService +Representation of a [Kubernetes Service.](https://kubernetes.io/docs/concepts/services-networking/service/) + +| Field | Description | +|-------|-------------| +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | UID of the kubernetes service | +| name | Name of the kubernetes service | +| created\_at | Timestamp of the creation time of the kubernetes service | +| deleted\_at | Timestamp of the deletion time of the kubernetes service | +| type | Type of kubernetes service e.g. `ClusterIP` | +| load\_balancer\_ip | IP of the load balancer when service type is `LoadBalancer` | +| ingress\_host | Hostname of the ingress endpoint, if any | +| ingress\_ip | IP of the ingress endpoint, if any | + +#### Relationships +- KubernetesService can serve KubernetesPods. + ``` + (KubernetesService)-[SERVES_POD]->(KubernetesPod) + ``` + +### KubernetesSecret +Representation of a [Kubernetes Secret.](https://kubernetes.io/docs/concepts/configuration/secret/) + +| Field | Description | +|-------|-------------| +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | UID of the kubernetes secret | +| name | Name of the kubernetes secret | +| created\_at | Timestamp of the creation time of the kubernetes secret | +| deleted\_at | Timestamp of the deletion time of the kubernetes secret | +| type | Type of kubernetes secret e.g. `Opaque` | + +#### Relationships +- KubernetesNamespace can have KubernetesSecrets. + ``` + (KubernetesNamespace)-[HAS_SECRET]->(KubernetesSecret) + ``` diff --git a/_sources/modules/lastpass/config.md.txt b/_sources/modules/lastpass/config.md.txt new file mode 100644 index 0000000000..3d8ebe7530 --- /dev/null +++ b/_sources/modules/lastpass/config.md.txt @@ -0,0 +1,9 @@ +## Lastpass Configuration + +.. _lastpass_config: + +Follow these steps to analyze Lastpass objects with Cartography. + +1. Prepare your Lastpass CID & ProvHash key. + 1. Get your CID (account number) and ProvHash from Lastpass [Where can I find the CID and API secret?](https://support.lastpass.com/help/where-can-i-find-the-cid-and-api-secret) + 1. Populate an environment variable with the CID and Provhash. You can pass the environment variable name via CLI with the `--lastpass-cid-env-var` and `--lastpass-provhash-env-var` parameter. diff --git a/_sources/modules/lastpass/index.rst.txt b/_sources/modules/lastpass/index.rst.txt new file mode 100644 index 0000000000..96a036e946 --- /dev/null +++ b/_sources/modules/lastpass/index.rst.txt @@ -0,0 +1,12 @@ +Lastpass +######## + +The lastpass module has the following coverage: + +* Users + +.. toctree:: + :hidden: + :glob: + + * diff --git a/_sources/modules/lastpass/schema.md.txt b/_sources/modules/lastpass/schema.md.txt new file mode 100644 index 0000000000..cbbff9a5bf --- /dev/null +++ b/_sources/modules/lastpass/schema.md.txt @@ -0,0 +1,45 @@ +## Lastpass Schema + +.. _lastpass_schema: + + +### Human + +Lastpass use Human node as pivot with other Identity Providers (GSuite, GitHub ...) + +Human nodes are not created by Lastpass module, link is made using analysis job. + + +#### Relationships + +- Human as an access to Lastpass + ``` + (Human)-[IDENTITY_LASTPASS]->(LastpassUser) + ``` + +### LastpassUser + +Representation of a single User in Lastpass + +| Field | Description | +|-------|--------------| +| firstseen| Timestamp of when a sync job first created this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | Lastpass ID | +| name | Full name of the user | +| email | User email | +| created | Timestamp of when the account was created | +| last_pw_change | Timestamp of the last master password change | +| last_login | Timestamp of the last login | +| neverloggedin | Flag indicating the user never logged in | +| disabled | Flag indicating accout is disabled | +| admin | Flag for admin account | +| totalscore | Lastpass security score (max 100) | +| mpstrength | Master password strenght (max 100) | +| sites | Number of site credentials stored | +| notes | Number of secured notes stored | +| formfills | Number of forms stored | +| applications | Number of applications (mobile) stored | +| attachments | Number of file attachments stored | +| password_reset_required | Flag indicating user requested password reset | +| multifactor | MFA method (null if None) | diff --git a/_sources/modules/okta/config.md.txt b/_sources/modules/okta/config.md.txt new file mode 100644 index 0000000000..df8fe9fd83 --- /dev/null +++ b/_sources/modules/okta/config.md.txt @@ -0,0 +1,12 @@ +## Okta Configuration + +.. _okta_config: + +Follow these steps to analyze Okta objects with Cartography. + +1. Prepare your Okta API token. + 1. Generate your API token by following the steps from the Okta [Create An API Token documentation](https://developer.okta.com/docs/guides/create-an-api-token/overview/) + 1. Populate an environment variable with the API token. You can pass the environment variable name via CLI with the `--okta-api-key-env-var` parameter. + 1. Use the CLI `--okta-org-id` parameter with the organization ID that you wish to query. The organization ID is the first part of the Okta URL for your organization. + 1. If you are using Okta to [administer AWS as a SAML provider](https://saml-doc.okta.com/SAML_Docs/How-to-Configure-SAML-2.0-for-Amazon-Web-Service#scenarioC) then the module will automatically match OktaGroups to the AWSRole they control access for. + - If you are using a regex other than the standard okta group to role regex `^aws\#\S+\#(?{{role}}[\w\-]+)\#(?{{accountid}}\d+)$` defined in [Step 5: Enabling Group Based Role Mapping in Okta](https://saml-doc.okta.com/SAML_Docs/How-to-Configure-SAML-2.0-for-Amazon-Web-Service#scenarioC) then you can specify your regex with the `--okta-saml-role-regex` parameter. diff --git a/_sources/modules/okta/index.rst.txt b/_sources/modules/okta/index.rst.txt new file mode 100644 index 0000000000..9bf98c36d8 --- /dev/null +++ b/_sources/modules/okta/index.rst.txt @@ -0,0 +1,19 @@ +Okta +#### + +The okta module has the following coverage: + +* Users +* Groups +* Organizations +* Roles +* Applications +* Factors +* Trusted Origins +* Reply URIs + +.. toctree:: + :hidden: + :glob: + + * diff --git a/_sources/modules/okta/schema.md.txt b/_sources/modules/okta/schema.md.txt new file mode 100644 index 0000000000..a66dc14b3d --- /dev/null +++ b/_sources/modules/okta/schema.md.txt @@ -0,0 +1,267 @@ +## Okta Schema + +.. _okta_schema: + +### OktaOrganization + +Representation of an [Okta Organization](https://developer.okta.com/docs/concepts/okta-organizations/). + + +| Field | Description | +|-------|--------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The name of the Okta Organization, e.g. "lyft" | +| name | The name of the Okta Organization, e.g. "lyft" + +#### Relationships + +- An OktaOrganization contains OktaUsers + + ``` + (OktaOrganization)-[RESOURCE]->(OktaUser) + ``` + +- An OktaOrganization contains OktaGroups. + + ``` + (OktaOrganization)-[RESOURCE]->(OktaGroup) + ``` +- An OktaOrganization contains OktaApplications + + ``` + (OktaOrganization)-[RESOURCE]->(OktaApplication) + ``` +- An OktaOrganization has OktaTrustedOrigins + + ``` + (OktaOrganization)-[RESOURCE]->(OktaTrustedOrigin) + ``` +- An OktaOrganization has OktaAdministrationRoles + + ``` + (OktaOrganization)-[RESOURCE]->(OktaAdministrationRole) + ``` + +### OktaUser + +Representation of an [Okta User](https://developer.okta.com/docs/reference/api/users/#user-object). + +| Field | Description | +|-------|--------------| +| id | user id | +| first_name | user first name | +| last_name | user last name | +| login | user usernmae used to login (usually email) | +| email | user email | +| second_email | user secondary email | +| mobile_phone | user mobile phone | +| created | date and time of creation | +| activated | date and time of activation | +| status_changed | date and time of the last state change | +| last_login | date and time of last login | +| okta_last_updated | date and time of last user property changes | +| password_changed | date and time of last password change | +| transition_to_status | date and time of last state transition change | +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | + +#### Relationships + + - An OktaOrganization contains OktaUsers + ``` + (OktaUser)<-[RESOURCE]->(OktaOrganization) + ``` + - OktaUsers are assigned OktaApplication + + ``` + (OktaUser)-[APPLICATION]->(OktaApplication) + ``` + - OktaUser is an identity for a Human + + ``` + (OktaUser)<-[IDENTITY_OKTA]-(Human) + ``` + - An OktaUser can be a member of an OktaGroup + ``` + (OktaUser)-[MEMBER_OF_OKTA_GROUP]->(OktaGroup) + ``` + - An OktaUser can be a member of an OktaAdministrationRole + ``` + (OktaUser)-[MEMBER_OF_OKTA_ROLE]->(OktaAdministrationRole) + ``` + - OktaUsers can have authentication factors + ``` + (OktaUser)-[FACTOR]->(OktaUserFactor) + ``` + +### OktaGroup + +Representation of an [Okta Group](https://developer.okta.com/docs/reference/api/groups/#group-object). + +| Field | Description | +|-------|--------------| +| id | application id | +| name | group name | +| description | group description | +| sam_account_name | windows SAM account name mapped +| dn | group dn | +| windows_domain_qualified_name | windows domain name | +| external_id | group foreign id | +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | + +#### Relationships + + - OktaOrganizations contain OktaGroups + ``` + (OktaGroup)<-[RESOURCE]->(OktaOrganizations) + ``` + - OktaApplications can be assigned to OktaGroups + + ``` + (OktaGroup)-[APPLICATION]->(OktaApplication) + ``` + - An OktaUser can be a member of an OktaGroup + ``` + (OktaUser)-[MEMBER_OF_OKTA_GROUP]->(OktaGroup) + ``` + - An OktaGroup can be a member of an OktaAdministrationRole + ``` + (OktaGroup)-[MEMBER_OF_OKTA_ROLE]->(OktaAdministrationRole) + ``` + +### OktaApplication + +Representation of an [Okta Application](https://developer.okta.com/docs/reference/api/apps/#application-object). + +| Field | Description | +|-------|--------------| +| id | application id | +| name | application name | +| label | application label | +| created | application creation date | +| okta_last_updated | date and time of last application property changes | +| status | application status | +| activated | application activation state | +| features | application features | +| sign_on_mode | application signon mode | +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | + +#### Relationships + + - OktaApplication is a resource of an OktaOrganization + ``` + (OktaApplication)<-[RESOURCE]->(OktaOrganization) + ``` + - OktaGroups can be assigned OktaApplications + + ``` + (OktaGroup)-[APPLICATION]->(OktaApplication) + ``` + - OktaUsers are assigned OktaApplications + + ``` + (OktaUser)-[APPLICATION]->(OktaApplication) + ``` +- OktaApplications have ReplyUris + + ``` + (ReplyUri)-[REPLYURI]->(OktaApplication) + ``` + +### OktaUserFactor + +Representation of Okta User authentication [Factors](https://developer.okta.com/docs/reference/api/factors/#factor-object). + +| Field | Description | +|-------|--------------| +| id | factor id | +| factor_type | factor type | +| provider | factor provider | +| status | factor status | +| created | factor creation date and time | +| okta_last_updated | date and time of last property changes | +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | + +#### Relationships + + - OktaUsers can have authentication Factors + ``` + (OktaUser)-[FACTOR]->(OktaUserFactor) + ``` + +### OktaTrustedOrigin + +Representation of an [Okta Trusted Origin](https://developer.okta.com/docs/reference/api/trusted-origins/#trusted-origin-object) for login/logout or recovery operations. + +| Field | Description | +|-------|--------------| +| id | trusted origin id | +| name | name | +| scopes | array of scope | +| status | status | +| created | date & time of creation in okta | +| create_by | id of user who created the trusted origin | +| okta_last_updated | date and time of last property changes | +| okta_last_updated_by | id of user who last updated the trusted origin | +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | + +#### Relationships + +- An OktaOrganization has OktaTrustedOrigins. + + ``` + (OktaOrganization)-[RESOURCE]->(OktaTrustedOrigin) + ``` + +### OktaAdministrationRole + +Representation of an [Okta Administration Role](https://developer.okta.com/docs/reference/api/roles/#role-object). + +| Field | Description | +|-------|--------------| +| id | role id mapped to the type | +| type | role type | +| label | role label | +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | + +#### Relationships + + - OktaUsers can be members of OktaAdministrationRoles + ``` + (OktaUser)-[MEMBER_OF_OKTA_ROLE]->(OktaAdministrationRole) + ``` + - An OktaGroup can be a member of an OktaAdministrationRolee + ``` + (OktaGroup)-[MEMBER_OF_OKTA_ROLE]->(OktaAdministrationRole) + ``` +- An OktaOrganization contains OktaAdministrationRoles + + ``` + (OktaOrganization)-[RESOURCE]->(OktaAdministrationRole) + ``` + +### Reply Uri + +Representation of [Okta Application ReplyUri](https://developer.okta.com/docs/reference/api/apps/). + +| Field | Description | +|-------|--------------| +| id | uri the app can send the reply to | +| uri | uri the app can send the reply to | +| valid | is the DNS of the reply uri valid. Invalid replyuris can lead to oath phishing | +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | + +#### Relationships + + - OktaApplications have ReplyUris + + ``` + (ReplyUri)-[REPLYURI]->(OktaApplication) + ``` diff --git a/_sources/modules/pagerduty/config.md.txt b/_sources/modules/pagerduty/config.md.txt new file mode 100644 index 0000000000..bba83233f2 --- /dev/null +++ b/_sources/modules/pagerduty/config.md.txt @@ -0,0 +1,10 @@ +## Pagerduty Configuration + +.. _pagerduty_config: + +Follow these steps to analyze PagerDuty objects with Cartography. + +1. Prepare your PagerDuty API key. + 1. Generate your API token by following the steps from the PagerDuty [Generating API Keys documentation](https://support.pagerduty.com/docs/generating-api-keys) + 1. Populate an environment variable with the API key. You can pass the environment variable name via CLI with the `--pagerduty-api-key-env-var` parameter. + 1. You can set the timeout for pagerduty requests via the CLI with `--pagerduty-request-timeout` parameter. diff --git a/_sources/modules/pagerduty/index.rst.txt b/_sources/modules/pagerduty/index.rst.txt new file mode 100644 index 0000000000..d55900051d --- /dev/null +++ b/_sources/modules/pagerduty/index.rst.txt @@ -0,0 +1,18 @@ +PagerDuty +######### + +The pagerduty module has the following coverage: + +* Users +* Teams +* Services +* Schedules +* Escalation Policies +* Integrations +* Vendors + +.. toctree:: + :hidden: + :glob: + + * diff --git a/_sources/modules/pagerduty/schema.md.txt b/_sources/modules/pagerduty/schema.md.txt new file mode 100644 index 0000000000..2647be76b4 --- /dev/null +++ b/_sources/modules/pagerduty/schema.md.txt @@ -0,0 +1,222 @@ +## Pagerduty Schema + +.. _pagerduty_schema: + +### PagerDutyEscalationPolicy + +Representation of a [PagerDuty Escalation Policy](https://developer.pagerduty.com/api-reference/c2NoOjI3NDgwMjE-escalation-policy) + +| Field | Description | +|-------|--------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The ID of the escalation policy | +| html\_url | the API show URL at which the object is accessible | +| type | The type of this pagerduty object (escalation\_policy) | +| summary | A short-form, server-generated string that provides succinct, important information about an object suitable for primary labeling of an entity in a client. In many cases, this will be identical to name, though it is not intended to be an identifier. | +| on\_call\_handoff\_notifications | Determines how on call handoff notifications will be sent for users on the escalation policy. Defaults to "if\_has\_services". | +| name | The name of the escalation policy. | +| num\_loops | The number of times the escalation policy will repeat after reaching the end of its escalation. | + +#### Relationships + +- A PagerDutyEscalationPolicy has PagerDutyEscalationPolicyRules + + ``` + (PagerDutyEscalationPolicy)-[HAS\_RULE]->(PagerDutyEscalationPolicyRule) + ``` + +- A PagerDutyEscalationPolicy is associated with PagerDutyUsers + + ``` + (PagerDutyEscalationPolicy)-[ASSOCIATED\_WITH]->(PagerDutyUser) + ``` + +- A PagerDutyEscalationPolicy is associated with PagerDutySchedules + + ``` + (PagerDutyEscalationPolicy)-[ASSOCIATED\_WITH]->(PagerDutySchedule) + ``` + +- A PagerDutyEscalationPolicy is associated with PagerDutyServices + + ``` + (PagerDutyEscalationPolicy)-[ASSOCIATED\_WITH]->(PagerDutyService) + ``` + +- A PagerDutyEscalationPolicy is associated with PagerDutyTeams + + ``` + (PagerDutyEscalationPolicy)-[ASSOCIATED\_WITH]->(PagerDutyTeam) + ``` + +### PagerDutySchedule + +Representation of a [PagerDuty Schedule](https://developer.pagerduty.com/api-reference/c2NoOjI3NDgwMzU-schedule) + +| Field | Description | +|-------|--------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The ID of the schedule | +| html\_url | the API show URL at which the object is accessible | +| type | The type of this pagerduty object (schedule) | +| summary | A short-form, server-generated string that provides succinct, important information about an object suitable for primary labeling of an entity in a client. In many cases, this will be identical to name, though it is not intended to be an identifier. | +| name | The name of the schedule. | +| time\_zone | The time zone of the schedule | +| description | The description of the schedule | + +#### Relationships + +- A PagerDutySchedule has PagerDutyScheduleLayers + + ``` + (PagerDutySchedule)-[HAS\_LAYER]->(PagerDutyScheduleLayer) + ``` + +### PagerDutyScheduleLayer + +Representation of a layer in a [PagerDuty Schedule](https://developer.pagerduty.com/api-reference/c2NoOjI3NDgwMzU-schedule) + +| Field | Description | +|-------|--------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The ID of the schedule layer | +| schedule\_id | The ID of the schedule this layer is attached to. | +| start | The start time of this layer | +| end | The end time of this layer. If null, the layer does not end. | +| rotation\_virtual\_start | The effective start time of the layer. This can be before the start time of the schedule. | +| rotation\_turn\_length\_seconds | The duration of each on-call shift in seconds. | + +#### Relationships + +No relationships originating from PagerDutyScheduleLayer + +### PagerDutyService + +Representation of a [PagerDuty Service](https://developer.pagerduty.com/api-reference/c2NoOjI3NDgwMjc-service) + +| Field | Description | +|-------|--------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The ID of the service | +| html\_url | the API show URL at which the object is accessible | +| type | The type of this pagerduty object (service) | +| summary | A short-form, server-generated string that provides succinct, important information about an object suitable for primary labeling of an entity in a client. In many cases, this will be identical to name, though it is not intended to be an identifier. | +| name | The name of this service | +| description | The user-provided description of the service. | +| auto\_resolve\_timeout | Time in seconds that an incident is automatically resolved if left open for that long. Value is null if the feature is disabled. Value must not be negative. Setting this field to 0, null (or unset in POST request) will disable the feature. | +| acknowledgement\_timeout | Time in seconds that an incident changes to the Triggered State after being Acknowledged. Value is null if the feature is disabled. Value must not be negative. Setting this field to 0, null (or unset in POST request) will disable the feature. | +| created\_at | The date/time when this service was created | +| status | The current state of the Service. | +| alert\_creation | Whether a service creates only incidents, or both alerts and incidents. A service must create alerts in order to enable incident merging. | +| alert\_grouping\_parameters\_type | The type of Alert Grouping. | +| incident\_urgency\_rule\_type | The type of incident urgency: whether it's constant, or it's dependent on the support hours. | +| incident\_urgency\_rule\_during\_support\_hours\_type | The type of incident urgency: whether it's constant, or it's dependent on the support hours. | +| incident\_urgency\_rule\_during\_support\_hours\_urgency | The incidents' urgency, if type is constant. | +| incident\_urgency\_rule\_outside\_support\_hours\_type | The type of incident urgency: whether it's constant, or it's dependent on the support hours. | +| incident\_urgency\_rule\_outside\_support\_hours\_urgency | The incidents' urgency, if type is constant. | +| support\_hours\_type | The type of support hours | +| support\_hours\_time\_zone | The time zone for the support hours | +| support\_hours\_start\_time | The support hours' starting time of day (date portion is ignored) | +| support\_hours\_end\_time | support\_hours\_end\_time | +| support\_hours\_days\_of\_week | (no description) | + +#### Relationships + +- A PagerDutyService has PagerDutyIntegrations + + ``` + (PagerDutyService)-[HAS\_INTEGRATION]->(PagerDutyIntegration) + ``` + +### PagerDutyIntegration + +Representation of a [PagerDuty Integration](https://developer.pagerduty.com/api-reference/c2NoOjI3NDgwMzA-integration) + +| Field | Description | +|-------|--------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The ID of the integration | +| html\_url | the API show URL at which the object is accessible | +| type | The type of this pagerduty object (integration) | +| summary | A short-form, server-generated string that provides succinct, important information about an object suitable for primary labeling of an entity in a client. In many cases, this will be identical to name, though it is not intended to be an identifier. | +| name | The name of this integration | +| created\_at | The date/time when this integration was created. | + +#### Relationships + +- A PagerDutyIntegration has PagerDutyVendors + + ``` + (PagerDutyIntegration)-[HAS\_VENDOR]->(PagerDutyVendor) + ``` + +### PagerDutyTeam + +Representation of a [PagerDuty Team](https://developer.pagerduty.com/api-reference/c2NoOjI3NDgwMTc-team) + +| Field | Description | +|-------|--------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The ID of the team | +| html\_url | the API show URL at which the object is accessible | +| type | The type of this pagerduty object (team) | +| summary | A short-form, server-generated string that provides succinct, important information about an object suitable for primary labeling of an entity in a client. In many cases, this will be identical to name, though it is not intended to be an identifier. | +| name | The name of the team | +| description | The description of the team | +| default\_role | (no description, but returned by API) | + +#### Relationships + +- A PagerDutyTeam is associated with PagerDutyServices + + ``` + (PagerDutyTeam)-[ASSOCIATED\_WITH]->(PagerDutyServices) + ``` + +### PagerDutyUser + +Representation of a [PagerDuty User](https://developer.pagerduty.com/api-reference/c2NoOjI3NDgwMTU-user) + +| Field | Description | +|-------|--------------| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The ID of the user | +| html\_url | the API show URL at which the object is accessible | +| type | The type of this pagerduty object (user) | +| summary | A short-form, server-generated string that provides succinct, important information about an object suitable for primary labeling of an entity in a client. In many cases, this will be identical to name, though it is not intended to be an identifier. | +| name | The name of the user | +| email | The user's email address +| time\_zone | The preferred time zone name. If null, the account's time zone will be used. | +| color | The schedule color | +| role | The user role. Account must have the read\_only\_users ability to set a user as a read\_only\_user or a read\_only\_limited\_user, and must have advanced permissions abilities to set a user as observer or restricted\_access. | +| avatar\_url | The URL of the user's avatar. | +| description | The user's bio. | +| invitation\_sent | If true, the user has an outstanding invitation. | +| job\_title | The user's title | + +#### Relationships + +- A PagerDutyUser is a member of PagerDutySchedules + + ``` + (PagerDutyUser)-[MEMBER\_OF]->(PagerDutySchedule) + ``` + +- A PagerDutyUser is a member of PagerDutyScheduleLayers + + ``` + (PagerDutyUser)-[MEMBER\_OF]->(PagerDutyScheduleLayer) + ``` + +- A PagerDutyUser is a member of PagerDutyTeams + + ``` + (PagerDutyUser)-[MEMBER\_OF]->(PagerDutyTeam) + ``` diff --git a/_sources/modules/semgrep/config.md.txt b/_sources/modules/semgrep/config.md.txt new file mode 100644 index 0000000000..6beb6616c5 --- /dev/null +++ b/_sources/modules/semgrep/config.md.txt @@ -0,0 +1,9 @@ +## Semgrep Configuration + +.. _semgrep_config: + +Follow these steps to ingest Semgrep findings with Cartography. + +1. Create a token with *Agent (CI)* and *Web API scopes* [Creating a SEMGREP_APP_TOKEN](https://semgrep.dev/docs/semgrep-ci/running-semgrep-ci-with-semgrep-cloud-platform/#creating-a-semgrep_app_token). +1. Populate an environment variable with the secrets value of the token +1. Pass the environment variable name to the `--semgrep-app-token-env-var` CLI arg. diff --git a/_sources/modules/semgrep/index.rst.txt b/_sources/modules/semgrep/index.rst.txt new file mode 100644 index 0000000000..54a4d625b9 --- /dev/null +++ b/_sources/modules/semgrep/index.rst.txt @@ -0,0 +1,13 @@ +Semgrep +#### + +The Semgrep module has the following coverage: + +* Deployment +* SCA Findings + +.. toctree:: + :hidden: + :glob: + + * diff --git a/_sources/modules/semgrep/schema.md.txt b/_sources/modules/semgrep/schema.md.txt new file mode 100644 index 0000000000..415e946c2c --- /dev/null +++ b/_sources/modules/semgrep/schema.md.txt @@ -0,0 +1,91 @@ +## Semgrep Schema + +.. _semgrep_schema: + +### SemgrepDeployment + +Represents a Semgrep [Deployment](https://semgrep.dev/api/v1/docs/#tag/Deployment), a unit encapsulating a security organization inside Semgrep Cloud. Works as the parent of all other Semgrep resources. + +| Field | Description | +|-------|--------------| +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | Unique integer id representing the deployment | +| **slug** | Lowercase string id representing the deployment to query the API | +| **name** | Name of security organization connected to the deployment | + +#### Relationships + +- A SemgrepDeployment contains SemgrepSCAFinding's + + ``` + (SemgrepDeployment)-[RESOURCE]->(SemgrepSCAFinding) + ``` + +- A SemgrepDeployment contains SemgrepSCALocation's + + + ``` + (SemgrepDeployment)-[RESOURCE]->(SemgrepSCALocation) + ``` + + ``` + +### SemgrepSCAFinding + +Represents a [Semgre Supply Chain](https://semgrep.dev/docs/semgrep-supply-chain/overview/) finding. This is, a vulnerability in a dependency of a project discovered by Semgrep performing software composition analysis (SCA) and code reachability analysis. Before ingesting this node, make sure you have run Semgrep CI and that it's connected to Semgrep Cloud Platform [Running Semgrep CI with Semgrep Cloud Platform](https://semgrep.dev/docs/semgrep-ci/running-semgrep-ci-with-semgrep-cloud-platform/). + +| Field | Description | +|-------|--------------| +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | A composed id based using the repository path and the rule that triggered the finding | +| **rule_id** | The rule that triggered the finding | +| **repository** | The repository path where the finding was discovered | +| summary | A short title summarizing of the finding | +| description | Description of the vulnerability. | +| package_manager | The ecosystem of the dependency where the finding was discovered (e.g. pypi, npm, maven) | +| severity | Severity of the finding (e.g. CRITICAL, HIGH, MEDIUM, LOW) | +| cve_id | CVE id of the vulnerability from NVD. Check [cve_schema](../cve/schema.md) | +| reachability_check | Whether the vulnerability reachability is confirmed, not confirmed or needs to be manually confirmed | +| reachability_condition | Description of the reachability condition (e.g. reachable if code is used in X way) | +| reachability | Whether the vulnerability is reachable or not | +| transitivity | Whether the vulnerability is transitive or not (e.g. dependency, transitive) | +| dependency | Dependency where the finding was discovered. Includes dependency name and version | +| dependency_fix | Dependency version that fixes the vulnerability | +| ref_urls | List of reference urls for the finding | +| dependency_file | Path of the file where the finding was discovered (e.g. lock.json, requirements.txt) | +| dependency_file_url | URL of the file where the finding was discovered | +| scan_time | Date and time when the finding was discovered in UTC | + + +#### Relationships + +- An SemgrepSCAFinding connected to a GithubRepository (optional) + + ``` + (SemgrepSCAFinding)-[FOUND_IN]->(GithubRepository) + ``` + +- A SemgrepSCAFinding vulnerable dependency usage at SemgrepSCALocation (optional) + + ``` + (SemgrepSCAFinding)-[USAGE_AT]->(SemgrepSCALocation) + ``` + + +### SemgrepSCALocation + +Represents the location in a repository where a vulnerable dependency is used in a way that can trigger the vulnerability. + +| Field | Description | +|-------|--------------| +| firstseen | Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| **id** | Unique id identifying the location of the finding | +| path | Path of the file where the usage was discovered | +| start_line | Line where the usage starts | +| start_col | Column where the usage starts | +| end_line | Line where the usage ends | +| end_col | Column where the usage ends | +| url | URL of the file where the usage was discovered | diff --git a/_sources/ops.md.txt b/_sources/ops.md.txt new file mode 100644 index 0000000000..9a6e54878d --- /dev/null +++ b/_sources/ops.md.txt @@ -0,0 +1,49 @@ +# Cartography operations guide + +This document contains tips for running Cartography in production. + +## Maintaining a up-to-date picture of your infrastructure + +Running `cartography` ensures that your Neo4j instance contains the most recent snapshot of your infrastructure. Here's +how that process works. + +### Update tags + +Each sync run has an `update_tag` associated with it, +which is the [Unix timestamp of when the sync started](https://github.com/lyft/cartography/blob/8d60311a10156cd8aa16de7e1fe3e109cc3eca0f/cartography/sync.py#L131-L134). +See our [docs for more details](../dev/writing-intel-modules.md#handling-cartographys-update_tag). + +### Cleanup jobs + +Each node and relationship created or updated during the sync will have their `lastupdated` field set to the +`update_tag`. At the end of a sync run, nodes and relationships with out-of-date `lastupdated` fields are considered +stale and will be deleted via a [cleanup job](../dev/writing-intel-modules.md#cleanup). + +### Sync frequency + +To keep data updated, you can run `cartography` as part of a periodic script (cronjobs in Linux, scheduled tasks in +Windows). Determine your needs for data freshness and adjust accordingly. + +## Observability + +### statsd + +Cartography can be configured to send metrics to a [statsd](https://github.com/statsd/statsd) server. Specify the +`--statsd-enabled` flag when running `cartography` for sync execution times to be recorded and sent to +`127.0.0.1:8125` by default (these options are also configurable with the `--statsd-host` and `--statsd-port` options). +You can also provide your own `--statsd-prefix` to make these metrics easier to find in your own environment. + +## Docker image + +A production-ready docker image is available in [GitHub Container Registry](https://github.com/lyft/cartography/pkgs/container/cartography). We recommend that you avoid using the `:latest` tag and instead +use the tag or digest associated with your desired release version, e.g. + +```bash +docker pull ghcr.io/lyft/cartography:0.61.0 +``` + +This image can then be ran with any of your desired command line flags: + +```bash +docker run --rm ghcr.io/lyft/cartography:0.61.0 --help +``` diff --git a/_sources/usage/drift-detect.md.txt b/_sources/usage/drift-detect.md.txt new file mode 100644 index 0000000000..f0ebe83f8b --- /dev/null +++ b/_sources/usage/drift-detect.md.txt @@ -0,0 +1,166 @@ +# How to use Drift-Detection +Drift-Detection is a Cartography module that allows you to track changes of query results over time. + +## A Quick Example: Tracking internet-exposed EC2 instances +The quickest way to get started using drift-detection is through an example. We showed you [how we mark EC2 instances as internet-exposed with Cartography analysis jobs](../dev/writing-analysis-jobs.md#example-job-which-of-my-ec2-instances-is-accessible-to-any-host-on-the-internet), and now we can use drift-detection to monitor when these instances are added or removed from our accounts over time! + +### Setup +1. **Specify a** `${DRIFT_DETECTION_DIRECTORY}` on the machine that runs `cartography`. This can be any folder where you have read and write access to. + +2. **Set up a folder structure** that looks like this: + + ``` + ${DRIFT_DETECTION_DIRECTORY}/ + | + |----internet-exposure-query/ + | + |----another-query-youre-interested-in/ + | + |----yet-another-query-to-track-over-time/ + ``` + + As shown here, your `${DRIFT_DETECTION_DIRECTORY}` contains one or more `${QUERY_DIRECTORY}s`. + +3. **Create a template file** + + Save the below contents as `${DRIFT_DETECTION_DIRECTORY}/internet-exposure-query/template.json`: + + ``` + { + "name": "Internet Exposed EC2 Instances", + "validation_query": "match (n:EC2Instance) where n.exposed_internet = True return n.instancetype, n.privateipaddress, n.publicdnsname, n.exposed_internet_type" + "properties": [], + "results": [] + } + ``` + + - `name` is a helpful name describing the query. + - `validation_query` is the neo4j Cypher query to track over time. In this case, we have simply asked Neo4j to return `instancetype`, `privateipaddress`, `publicdnsname`, and `exposed_internet_type` from EC2Instances that Cartography has identified as accessible from the internet. When writing your own queries, note that drift-detection only supports `MATCH` queries (i.e. read operations). `MERGE` queries (write operations) are not supported. + - `properties`: Leave this as an empty array. This field is a placeholder that will be filled. + - `results`: Leave this as an empty array. This field is a placeholder that will be filled. + +4. **Create a shortcut file** + + Save the below contents as `${DRIFT_DETECTION_DIRECTORY}/internet-exposure-query/shortcut.json`: + + ``` + { + "name": "Internet Exposed EC2 Instances", + "shortcuts": {} + } + ``` + + `name` should match the `name` you specified in `template.json`. + +All set 👍 + +### Running drift-detection + +1. **Run `get-state` to save results of a query to json** + + Run `cartography-detectdrift get-state --neo4j-uri --drift-detection-directory ${DRIFT_DETECTION_DIRECTORY}` + + The internet exposure query might return results that look like this: + + ``` + | n.instancetype | n.privateipaddress | n.publicdnsname | n.exposed_internet_type | + |---------------- |-------------------- |----------------------------- |------------------------- | + | c4.large | 10.255.255.251 | ec2.1.compute.amazonaws.com | [direct] | + | t2.micro | 10.255.255.252 | ec2.2.compute.amazonaws.com | [direct] | + | c4.large | 10.255.255.253 | ec2.3.compute.amazonaws.com | [direct, elb] | + | t2.micro | 10.255.255.254 | ec2.4.compute.amazonaws.com | [direct, elb] | + + ``` + and we should now see a new JSON file `.json` saved with information in this format: + + ``` + { + "name": "Internet Exposed EC2 Instances", + "validation_query": "match (n:EC2Instance) where n.exposed_internet = True return n.instancetype, n.privateipaddress, n.publicdnsname, n.exposed_internet_type" + "properties": ["n.instancetype", "n.privateipaddress", "n.publicdnsname", "n.exposed_internet_type"], + "results": [ + ["c4.large", "10.255.255.251", "ec2.1.compute.amazonaws.com", "direct"], + ["t2.micro", "10.255.255.252", "ec2.2.compute.amazonaws.com", "direct"], + ["c4.large", "10.255.255.253", "ec2.3.compute.amazonaws.com", "direct|elb"], + ["t2.micro", "10.255.255.254", "ec2.4.compute.amazonaws.com", "direct|elb"] + ] + } + ``` + + You can continually run `get-state` to save the results of a query to json. Each json state file will be named with the Unix timestamp of the time drift-detection was run. + +2. **Comparing state files** + + Now let's say a couple days go by and some new EC2 Instances were added to our AWS account. We run the `get-state` command once more and get another file `.json` which looks like this: + + ``` + { + "name": "Internet Exposed EC2 Instances", + "validation_query": "match (n:EC2Instance) where n.exposed_internet = True return n.instancetype, n.privateipaddress, n.publicdnsname, n.exposed_internet_type"" + "properties": ["n.instancetype", "n.privateipaddress", "n.publicdnsname", "n.exposed_internet_type"], + "results": [ + ["t2.micro", "10.255.255.250", "ec2.0.compute.amazonaws.com", "direct"], + ["c4.large", "10.255.255.251", "ec2.1.compute.amazonaws.com", "direct"], + ["t2.micro", "10.255.255.252", "ec2.2.compute.amazonaws.com", "direct"], + ["c4.large", "10.255.255.253", "ec2.3.compute.amazonaws.com", "direct|elb"], + ["c4.large", "10.255.255.255", "ec2.5.compute.amazonaws.com", "direct|elb"] + ] + } + ``` + + It looks like our results list has slightly changed. We can use `drift-detection` to quickly diff the two files: + + + `cartography-detectdrift get-drift --query-directory ${DRIFT_DETECTION_DIRECTORY}/internet-exposure-query --start-state .json --end-state .json` + + Finally, we should see the following messages pop up: + + ``` + Query Name: Internet Exposed EC2 Instances + Query Properties: ["n.instancetype", "n.privateipaddress", "n.publicdnsname", "n.exposed_internet_type"] + + New Query Results: + + n.instancetype: t2.micro + n.privateipaddress: 10.255.255.250 + n.publicdnsname: ec2.0.compute.amazonaws.com + n.exposed_internet_type: ['direct'] + + n.instancetype: c4.large + n.privateipaddress: 10.255.255.255 + n.publicdnsname: ec2.5.compute.amazonaws.com + n.exposed_internet_type: ['direct', 'elb'] + + Missing Query Results: + + n.instancetype: t2.micro + n.privateipaddress: 10.255.255.253 + n.publicdnsname: ec2.4.compute.amazonaws.com + n.exposed_internet_type: ['direct', 'elb'] + ``` + + This gives us a quick way to view infrastructure changes! + +### Using shortcuts instead of filenames to diff files + +It can be cumbersome to always type Unix timestamp filenames. To make this easier we can add `shortcuts` to diff two files without specifying the filename. This lets us bookmark certain states with whatever name we want. + +1. **Adding shortcuts** + + Let's try adding shortcuts. We will name the first state "first-run" and the second state "second-run" with + + `cartography-detectdrift add-shortcut --shortcut first-run --file .json` + + `cartography-detectdrift add-shortcut --shortcut second-run --file .json` + + We can even use aliases instead of filenames when adding shortcuts! + + `cartography-detectdrift add-shortcut --shortcut baseline --file most-recent` + +2. **Comparing state files with shortcuts** + + Now that we have shortcuts, we can now simply run + + `cartography-detectdrift get-drift --query-directory ${DRIFT_DETECTION_DIRECTORY}/internet-exposure-query --start-state first-run --end-state second-run` + +Important note: Each execution of `get-state` will automatically generate a shortcut in each query directory, `most-recent`, which will refer to the last state file successfully created in that directory. diff --git a/_sources/usage/index.rst.txt b/_sources/usage/index.rst.txt new file mode 100644 index 0000000000..f200d6f75d --- /dev/null +++ b/_sources/usage/index.rst.txt @@ -0,0 +1,7 @@ +.. toctree:: + + tutorial + schema + drift-detect + permissions-mapping + samplequeries diff --git a/_sources/usage/samplequeries.md.txt b/_sources/usage/samplequeries.md.txt new file mode 100644 index 0000000000..32ac8c6b37 --- /dev/null +++ b/_sources/usage/samplequeries.md.txt @@ -0,0 +1,105 @@ +## Sample queries + +### What [RDS](https://aws.amazon.com/rds/) instances are installed in my [AWS](https://aws.amazon.com/) accounts? +``` +MATCH (aws:AWSAccount)-[r:RESOURCE]->(rds:RDSInstance) +return * +``` + +### Which RDS instances have [encryption](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.Encryption.html) turned off? +``` +MATCH (a:AWSAccount)-[:RESOURCE]->(rds:RDSInstance{storage_encrypted:false}) +return a.name, rds.id +``` + +### Which [EC2](https://aws.amazon.com/ec2/) instances are exposed (directly or indirectly) to the internet? +``` +MATCH (instance:EC2Instance{exposed_internet: true}) +RETURN instance.instanceid, instance.publicdnsname +``` + +### Which [ELB](https://aws.amazon.com/elasticloadbalancing/) LoadBalancers are internet accessible? +``` +MATCH (elb:LoadBalancer{exposed_internet: true})—->(listener:ELBListener) +RETURN elb.dnsname, listener.port +ORDER by elb.dnsname, listener.port +``` + +### Which [ELBv2](https://aws.amazon.com/elasticloadbalancing/) LoadBalancerV2s (Application Load Balancers) are internet accessible? +``` +MATCH (elbv2:LoadBalancerV2{exposed_internet: true})—->(listener:ELBV2Listener) +RETURN elbv2.dnsname, listener.port +ORDER by elbv2.dnsname, listener.port +``` + +### Which [S3](https://aws.amazon.com/s3/) buckets have a policy granting any level of anonymous access to the bucket? +``` +MATCH (s:S3Bucket) +WHERE s.anonymous_access = true +RETURN s +``` + +### How many unencrypted RDS instances do I have in all my AWS accounts? + +``` +MATCH (a:AWSAccount)-[:RESOURCE]->(rds:RDSInstance) +WHERE rds.storage_encrypted = false +return a.name as AWSAccount, count(rds) as UnencryptedInstances +``` + +### What users have the TotallyFake Chrome extension installed? +``` +MATCH (u:GSuiteUser)-[r:INSTALLS]->(ext:ChromeExtension) +WHERE ext.name CONTAINS 'TotallyFake' +return ext.name, ext.version, u.email +``` + +### What users have installed extensions that are risky based on [CRXcavator scoring](https://crxcavator.io/docs#/risk_breakdown)? +Risk > 200 is evidence of 3 or more critical risks or many high risks in the extension. +``` +MATCH (u:GSuiteUser)-[r:INSTALLS]->(ext:ChromeExtension) +WHERE ext.risk_total > 200 +return ext.name, ext.version, u.email +``` + +### What languages are used in a given GitHub repository? +``` +MATCH (:GitHubRepository{name:"myrepo"})-[:LANGUAGE]->(lang:ProgrammingLanguage) +RETURN lang.name +``` + +### What are the dependencies used in a given GitHub repository? +``` +MATCH (:GitHubRepository{name:"myrepo"})-[edge:REQUIRES]->(dep:Dependency) +RETURN dep.name, edge.specifier, dep.version +``` + +If you want to filter to just e.g. Python libraries: +``` +MATCH (:GitHubRepository{name:"myrepo"})-[edge:REQUIRES]->(dep:Dependency:PythonLibrary) +RETURN dep.name, edge.specifier, dep.version +``` + +### Given a dependency, which GitHub repos depend on it? +Using boto3 as an example dependency: +``` +MATCH (dep:Dependency:PythonLibrary{name:"boto3"})<-[req:REQUIRES]-(repo:GitHubRepository) +RETURN repo.name, req.specifier, dep.version +``` + +### What are all the dependencies used across all GitHub repos? +Just the list of dependencies and their versions: +``` +MATCH (dep:Dependency) +RETURN DISTINCT dep.name AS name, dep.version AS version +ORDER BY dep.name +``` + +With info about which repos are using them: +``` +MATCH (repo:GitHubRepository)-[edge:REQUIRES]->(dep:Dependency) +RETURN repo.name, dep.name, edge.specifier, dep.version +``` +Lyft ingests this information into our internal data stack, +which has enabled us to throw BI tooling on top for easy reporting - +this is highly recommended! diff --git a/_sources/usage/schema.md.txt b/_sources/usage/schema.md.txt new file mode 100644 index 0000000000..a5f1d101d4 --- /dev/null +++ b/_sources/usage/schema.md.txt @@ -0,0 +1,36 @@ +# Cartography Schema + +## ℹ️ Quick notes on notation +- **Bolded words** in the schema tables indicate that this field is indexed, so your queries will run faster if you use these fields. + +- This isn't proper Neo4j syntax, but for the purpose of this document we will use this notation: + + ``` + (NodeTypeA)-[RELATIONSHIP_R]->(NodeTypeB, NodeTypeC, NodeTypeD, NodeTypeE) + ``` + + to mean a shortened version of this: + + ``` + (NodeTypeA)-[RELATIONSHIP_R]->(NodeTypeB) + (NodeTypeA)-[RELATIONSHIP_R]->(NodeTypeC) + (NodeTypeA)-[RELATIONSHIP_R]->(NodeTypeD) + (NodeTypeA)-[RELATIONSHIP_R]->(NodeTypeE) + ``` + + In words, this means that `NodeTypeA` has `RELATIONSHIP_R` pointing to `NodeTypeB`, and `NodeTypeA` has `RELATIONSHIP_R` pointing to `NodeTypeC`. + +- In these docs, more specific nodes will be decorated with `GenericNode::SpecificNode` notation. For example, if we have a `Car` node and a `RaceCar` node, we will refer to the `RaceCar` as `Car::RaceCar`. + +.. mdinclude:: ../modules/_cartography-metadata/schema.md +.. mdinclude:: ../modules/aws/schema.md +.. mdinclude:: ../modules/azure/schema.md +.. mdinclude:: ../modules/crxcavator/schema.md +.. mdinclude:: ../modules/digitalocean/schema.md +.. mdinclude:: ../modules/gcp/schema.md +.. mdinclude:: ../modules/github/schema.md +.. mdinclude:: ../modules/gsuite/schema.md +.. mdinclude:: ../modules/jamf/schema.md +.. mdinclude:: ../modules/kubernetes/schema.md +.. mdinclude:: ../modules/okta/schema.md +.. mdinclude:: ../modules/pagerduty/schema.md diff --git a/_sources/usage/tutorial.md.txt b/_sources/usage/tutorial.md.txt new file mode 100644 index 0000000000..f0cb52fa9b --- /dev/null +++ b/_sources/usage/tutorial.md.txt @@ -0,0 +1,190 @@ +## Usage Tutorial + +Once everything has been installed and synced, you can view the Neo4j web interface at http://localhost:7474. You can view the reference on this [here](https://neo4j.com/developer/guide-neo4j-browser/#_installing_and_starting_neo4j_browser). + +If you already know Neo4j and just need to know what are the nodes, attributes, and graph relationships for our representation of infrastructure assets, you can view our [sample queries](samplequeries.html). More sample queries are available at https://github.com/marco-lancini/cartography-queries. + +Otherwise, read on for this handhold-y tutorial filled with examples. Suppose we wanted to find out: + +### What [RDS](https://aws.amazon.com/rds/) instances are installed in my AWS accounts? +```cypher +MATCH (aws:AWSAccount)-[r:RESOURCE]->(rds:RDSInstance) +return * +``` + +![Visualization of RDS nodes and AWS nodes](../images/accountsandrds.png) + +In this query we asked Neo4j to find all `[:RESOURCE]` relationships from AWSAccounts to RDSInstances, and return the nodes and the `:RESOURCE` relationships. + +We will do more interesting things with this result next. + +#### ℹ️ Protip - customizing your view +You can adjust the node colors, sizes, and captions by clicking on the node type at the top of the query. For example, to change the color of an AWSAccount node, first click the "AWSAccount" icon at the top of the view to select the node type +![selecting an AWSAccount node](../images/selectnode.png) + +and then pick options on the menu that shows up at the bottom of the view like this: +![customizations](../images/customizeview.png) + + +### Which RDS instances have [encryption](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.Encryption.html) turned off? +```cypher +MATCH (a:AWSAccount)-[:RESOURCE]->(rds:RDSInstance{storage_encrypted:false}) +RETURN a.name, rds.id +``` + +![Unencrypted RDS instances](../images/unencryptedinstances.png) + +The results show up in a table because we specified attributes like `a.name` and `rds.id` in our return statement (as opposed to having it `return *`). We used the "{}" notation to have the query only return RDSInstances where `storage_encrypted` is set to `False`. + +If you want to go back to viewing the graph and not a table, simply make sure you don't have any attributes in your return statement -- use `return *` to return all nodes decorated with a variable label in your `MATCH` statement, or just return the specific nodes and relationships that you want. + +Let's look at some other AWS assets now. + +### Which [EC2](https://aws.amazon.com/ec2/) instances are directly exposed to the internet? +```cypher +MATCH (instance:EC2Instance{exposed_internet: true}) +RETURN instance.instanceid, instance.publicdnsname +``` +![EC2 instances open to the internet](../images/ec2-inet-open.png) + +These instances are open to the internet either through permissive inbound IP permissions defined on their EC2SecurityGroups or their NetworkInterfaces. + +If you know a lot about AWS, you may have noticed that EC2 instances [don't actually have an exposed_internet field](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_Instance.html). We're able to query for this because Cartography performs some [data enrichment](#data-enrichment) to add this field to EC2Instance nodes. + +### Which [S3](https://aws.amazon.com/s3/) buckets have a policy granting any level of anonymous access to the bucket? +```cypher +MATCH (s:S3Bucket) +WHERE s.anonymous_access = true +RETURN s +``` + +![S3 buckets that allow anon access](../images/anonbuckets.png) + +These S3 buckets allow for any user to read data from them anonymously. Similar to the EC2 instance example above, S3 buckets returned by the S3 API [don't actually have an anonymous_access field](https://docs.aws.amazon.com/AmazonS3/latest/API/API_Bucket.html) and this field is added by one of Cartography's [data augmentation steps](#data-augmentation). + +A couple of other things to notice: instead of using the "{}" notation to filter for anonymous buckets, we can use SQL-style `WHERE` clauses. Also, we used the SQL-style `AS` operator to relabel our output header rows. + +### How many unencrypted RDS instances do I have in all my AWS accounts? + +Let's go back to analyzing RDS instances. In an earlier example we queried for RDS instances that have encryption turned off. We can aggregate this data by AWSAccount with a small change: + +```cypher +MATCH (a:AWSAccount)-[:RESOURCE]->(rds:RDSInstance) +WHERE rds.storage_encrypted = false +RETURN a.name as AWSAccount, count(rds) as UnencryptedInstances +``` +![Table of unencrypted RDS instances by AWS account](../images/unencryptedcounts.png) + + +### Given a node label, what other node labels can be connected to it? + +Suppose we wanted to know what other assets can be connected to a DNSRecord. We would ask the graph like this: + +```cypher +match (d:DNSRecord)--(n) +return distinct labels(n); +``` + +This says "what are the possible labels for all nodes connected to all DNSRecord nodes `d` in my graph?" Your answer might look like this: + +``` +["AWSDNSRecord", "DNSRecord"] +["AWSDNSZone", "DNSZone"] +["LoadBalancerV2"] +["NameServer"] +["ESDomain"] +["LoadBalancer"] +["EC2Instance", "Instance"] +``` + +You can then make the path more specific like this: + +```cypher +match (d:DNSRecord)--(:EC2Instance)--(n) +return distinct labels(n); +``` + +And then you can continue building your query. + +We also include [full schema docs](schema.html), but this way of building a query can be faster and more interactive. + + +### Given a node label, what are the possible property names defined on it? + +We can find what properties are available on an S3Bucket like this: + +```cypher +match (n:S3Bucket) return properties(n) limit 1; +``` + +The result will look like this: + +``` +{ + "bucket_key_enabled": false, + "creationdate": "2022-05-10 00:22:52+00:00", + "ignore_public_acls": true, + "anonymous_access": false, + "firstseen": 1652400141863, + "block_public_policy": true, + "versioning_status": "Enabled", + "block_public_acls": true, + "anonymous_actions": [], + "name": "my-fake-bucket-123", + "lastupdated": 1688605272, + "encryption_algorithm": "AES256", + "default_encryption": true, + "id": "my-fake-bucket-123", + "arn": "arn:aws:s3:::my-fake-bucket-123", + "restrict_public_buckets": false +} +``` + +Our [full schema docs](schema.html) describe all possible fields, but listing out properties this way lets you avoid switching between browser tabs. + + +### Learning more +If you want to learn more in depth about Neo4j and Cypher queries you can look at [this tutorial](https://neo4j.com/developer/cypher-query-language/) and see this [reference card](https://neo4j.com/docs/cypher-refcard/current/). + +### Data Enrichment + +.. _data-augmentation: + +Cartography adds custom attributes to nodes and relationships to point out security-related items of interest. Unless mentioned otherwise these data augmentation jobs are stored in `cartography/data/jobs/analysis`. Here is a summary of all of Cartography's custom attributes. + +- `exposed_internet` indicates whether the asset is accessible to the public internet. + + - **Elastic Load Balancers**: The `exposed_internet` flag is set to `True` when the load balancer's `scheme` field is set to `internet-facing`, and the load balancer has an attached source security group with rules allowing `0.0.0.0/0` ingress on ports or port ranges matching listeners on the load balancer. This scheme indicates that the load balancer has a public DNS name that resolves to a public IP address. + + - **Application Load Balancers**: The `exposed_internet` flag is set to `True` when the load balancer's `scheme` field is set to `internet-facing`, and the load balancer has an attached security group with rules allowing `0.0.0.0/0` ingress on ports or port ranges matching listeners on the load balancer. This scheme indicates that the load balancer has a public DNS name that resolves to a public IP address. + + - **EC2 instances**: The `exposed_internet` flag on an EC2 instance is set to `True` when any of following apply: + + - The instance is part of an EC2 security group or is connected to a network interface connected to an EC2 security group that allows connectivity from the 0.0.0.0/0 subnet. + + - The instance is connected to an Elastic Load Balancer that has its own `exposed_internet` flag set to `True`. + + - The instance is connected to a TargetGroup which is attached to a Listener on an Application Load Balancer (elbv2) that has its own `exposed_internet` flag set to `True`. + + - **ElasticSearch domain**: `exposed_internet` is set to `True` if the ElasticSearch domain has a policy applied to it that makes it internet-accessible. This policy determination is made by using the [policyuniverse](https://github.com/Netflix-Skunkworks/policyuniverse) library. The code for this augmentation is implemented at `cartography.intel.aws.elasticsearch._process_access_policy()`. + +- `anonymous_access` indicates whether the asset allows access without needing to specify an identity. + + - **S3 buckets**: `anonymous_access` is set to `True` on an S3 bucket if this bucket has an S3Acl with a policy applied to it that allows the [predefined AWS "Authenticated Users" or "All Users" groups](https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#specifying-grantee-predefined-groups) to access it. These determinations are made by using the [policyuniverse](https://github.com/Netflix-Skunkworks/policyuniverse) library. + +### Extending Cartography with Analysis Jobs +You can add your own custom attributes and relationships without writing Python code! Here's [how](../dev/writing-analysis-jobs.html). + +### Mapping AWS Access Permissions +Cartography can map permissions between IAM Principals and resources in the graph. Here's [how](../modules/aws/permissions-mapping.html). + + +### Permalinking Bookmarklet + +You can set up a bookmarklet that lets you quickly get a permalink to a Cartography query. To do so, add a bookmark with the following contents as the URL - make sure to replace `neo4j.contoso.com:7474` with your instance of Neo4j: + +```javascript +javascript:(() => { const query = document.querySelectorAll('article label span')[0].innerText; if (query === ':server connect') { console.log('no query has been run!'); return; } const searchParams = new URLSearchParams(); searchParams.append('connectURL', 'bolt://neo4j:neo4j@neo4j.contoso.net:7687'); searchParams.append('cmd', 'edit'); searchParams.append('arg', query.replaceAll(/\r /g, '\r')); newURL = `http://neo4j.contoso.net:7474/browser/?${searchParams}`; window.open(newURL, '_blank', 'noopener'); })() +``` + +Then, any time you are in the web interface, you can click the bookmarklet to open a new tab with a permalink to your most recently executed query in the URL bar. diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 0000000000..603f6a8798 --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,905 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 450px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a.brackets:before, +span.brackets > a:before{ + content: "["; +} + +a.brackets:after, +span.brackets > a:after { + content: "]"; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +dl.footnote > dt, +dl.citation > dt { + float: left; + margin-right: 0.5em; +} + +dl.footnote > dd, +dl.citation > dd { + margin-bottom: 0em; +} + +dl.footnote > dd:after, +dl.citation > dd:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dt:after { + content: ":"; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 0000000000..8cbf1b161a --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,323 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) { + this.initOnKeyListeners(); + } + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated === 'undefined') + return string; + return (typeof translated === 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated === 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) === 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this === '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + $(document).keydown(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box, textarea, dropdown or button + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT' + && activeElementType !== 'BUTTON' && !event.altKey && !event.ctrlKey && !event.metaKey + && !event.shiftKey) { + switch (event.keyCode) { + case 37: // left + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + break; + case 39: // right + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + break; + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 0000000000..4daa6b50bd --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,12 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: '', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false +}; \ No newline at end of file diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 0000000000..a858a410e4 Binary files /dev/null and b/_static/file.png differ diff --git a/_static/fonts/font-awesome.css b/_static/fonts/font-awesome.css new file mode 100644 index 0000000000..b476b53e33 --- /dev/null +++ b/_static/fonts/font-awesome.css @@ -0,0 +1,4 @@ +/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url("specimen/FontAwesome.woff2") format("woff2"),url("specimen/FontAwesome.woff") format("woff"),url("specimen/FontAwesome.ttf") format("truetype")}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1,1);-ms-transform:scale(-1,1);transform:scale(-1,1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1,-1);-ms-transform:scale(1,-1);transform:scale(1,-1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-vcard:before,.fa-address-card:before{content:"\f2bb"}.fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto} \ No newline at end of file diff --git a/_static/fonts/material-icons.css b/_static/fonts/material-icons.css new file mode 100644 index 0000000000..63130b0120 --- /dev/null +++ b/_static/fonts/material-icons.css @@ -0,0 +1,13 @@ +/*! + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING, SOFTWARE + * DISTRIBUTED UNDER THE LICENSE IS DISTRIBUTED ON AN "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + * SEE THE LICENSE FOR THE SPECIFIC LANGUAGE GOVERNING PERMISSIONS AND + * LIMITATIONS UNDER THE LICENSE. + */@font-face{font-display:swap;font-family:"Material Icons";font-style:normal;font-weight:400;src:local("Material Icons"),local("MaterialIcons-Regular"),url("specimen/MaterialIcons-Regular.woff2") format("woff2"),url("specimen/MaterialIcons-Regular.woff") format("woff"),url("specimen/MaterialIcons-Regular.ttf") format("truetype")} \ No newline at end of file diff --git a/_static/fonts/specimen/FontAwesome.ttf b/_static/fonts/specimen/FontAwesome.ttf new file mode 100644 index 0000000000..35acda2fa1 Binary files /dev/null and b/_static/fonts/specimen/FontAwesome.ttf differ diff --git a/_static/fonts/specimen/FontAwesome.woff b/_static/fonts/specimen/FontAwesome.woff new file mode 100644 index 0000000000..400014a4b0 Binary files /dev/null and b/_static/fonts/specimen/FontAwesome.woff differ diff --git a/_static/fonts/specimen/FontAwesome.woff2 b/_static/fonts/specimen/FontAwesome.woff2 new file mode 100644 index 0000000000..4d13fc6040 Binary files /dev/null and b/_static/fonts/specimen/FontAwesome.woff2 differ diff --git a/_static/fonts/specimen/MaterialIcons-Regular.ttf b/_static/fonts/specimen/MaterialIcons-Regular.ttf new file mode 100644 index 0000000000..7015564ad1 Binary files /dev/null and b/_static/fonts/specimen/MaterialIcons-Regular.ttf differ diff --git a/_static/fonts/specimen/MaterialIcons-Regular.woff b/_static/fonts/specimen/MaterialIcons-Regular.woff new file mode 100644 index 0000000000..b648a3eea2 Binary files /dev/null and b/_static/fonts/specimen/MaterialIcons-Regular.woff differ diff --git a/_static/fonts/specimen/MaterialIcons-Regular.woff2 b/_static/fonts/specimen/MaterialIcons-Regular.woff2 new file mode 100644 index 0000000000..9fa2112520 Binary files /dev/null and b/_static/fonts/specimen/MaterialIcons-Regular.woff2 differ diff --git a/_static/images/favicon.png b/_static/images/favicon.png new file mode 100644 index 0000000000..76d17f57ad Binary files /dev/null and b/_static/images/favicon.png differ diff --git a/_static/images/icons/bitbucket.1b09e088.svg b/_static/images/icons/bitbucket.1b09e088.svg new file mode 100644 index 0000000000..cf58c14fbc --- /dev/null +++ b/_static/images/icons/bitbucket.1b09e088.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/_static/images/icons/bitbucket.svg b/_static/images/icons/bitbucket.svg new file mode 100644 index 0000000000..cf58c14fbc --- /dev/null +++ b/_static/images/icons/bitbucket.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/_static/images/icons/github.f0b8504a.svg b/_static/images/icons/github.f0b8504a.svg new file mode 100644 index 0000000000..3d13b19751 --- /dev/null +++ b/_static/images/icons/github.f0b8504a.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/_static/images/icons/github.svg b/_static/images/icons/github.svg new file mode 100644 index 0000000000..3d13b19751 --- /dev/null +++ b/_static/images/icons/github.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/_static/images/icons/gitlab.6dd19c00.svg b/_static/images/icons/gitlab.6dd19c00.svg new file mode 100644 index 0000000000..1d9fffa74f --- /dev/null +++ b/_static/images/icons/gitlab.6dd19c00.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/_static/images/icons/gitlab.svg b/_static/images/icons/gitlab.svg new file mode 100644 index 0000000000..1d9fffa74f --- /dev/null +++ b/_static/images/icons/gitlab.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/_static/javascripts/application.js b/_static/javascripts/application.js new file mode 100644 index 0000000000..7c724d2e4f --- /dev/null +++ b/_static/javascripts/application.js @@ -0,0 +1,2540 @@ +! function(e, t) { + for (var n in t) e[n] = t[n] +}(window, function(n) { + var r = {}; + + function i(e) { + if (r[e]) return r[e].exports; + var t = r[e] = { + i: e, + l: !1, + exports: {} + }; + return n[e].call(t.exports, t, t.exports, i), t.l = !0, t.exports + } + return i.m = n, i.c = r, i.d = function(e, t, n) { + i.o(e, t) || Object.defineProperty(e, t, { + enumerable: !0, + get: n + }) + }, i.r = function(e) { + "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, { + value: "Module" + }), Object.defineProperty(e, "__esModule", { + value: !0 + }) + }, i.t = function(t, e) { + if (1 & e && (t = i(t)), 8 & e) return t; + if (4 & e && "object" == typeof t && t && t.__esModule) return t; + var n = Object.create(null); + if (i.r(n), Object.defineProperty(n, "default", { + enumerable: !0, + value: t + }), 2 & e && "string" != typeof t) + for (var r in t) i.d(n, r, function(e) { + return t[e] + }.bind(null, r)); + return n + }, i.n = function(e) { + var t = e && e.__esModule ? function() { + return e.default + } : function() { + return e + }; + return i.d(t, "a", t), t + }, i.o = function(e, t) { + return Object.prototype.hasOwnProperty.call(e, t) + }, i.p = "", i(i.s = 13) +}([function(e, t, n) { + "use strict"; + var r = { + Listener: function() { + function e(e, t, n) { + var r = this; + this.els_ = Array.prototype.slice.call("string" == typeof e ? document.querySelectorAll(e) : [].concat(e)), this.handler_ = "function" == typeof n ? { + update: n + } : n, this.events_ = [].concat(t), this.update_ = function(e) { + return r.handler_.update(e) + } + } + var t = e.prototype; + return t.listen = function() { + var n = this; + this.els_.forEach(function(t) { + n.events_.forEach(function(e) { + t.addEventListener(e, n.update_, !1) + }) + }), "function" == typeof this.handler_.setup && this.handler_.setup() + }, t.unlisten = function() { + var n = this; + this.els_.forEach(function(t) { + n.events_.forEach(function(e) { + t.removeEventListener(e, n.update_) + }) + }), "function" == typeof this.handler_.reset && this.handler_.reset() + }, e + }(), + MatchMedia: function(e, t) { + this.handler_ = function(e) { + e.matches ? t.listen() : t.unlisten() + }; + var n = window.matchMedia(e); + n.addListener(this.handler_), this.handler_(n) + } + }, + i = { + Shadow: function() { + function e(e, t) { + var n = "string" == typeof e ? document.querySelector(e) : e; + if (!(n instanceof HTMLElement && n.parentNode instanceof HTMLElement)) throw new ReferenceError; + if (this.el_ = n.parentNode, !((n = "string" == typeof t ? document.querySelector(t) : t) instanceof HTMLElement)) throw new ReferenceError; + this.header_ = n, this.height_ = 0, this.active_ = !1 + } + var t = e.prototype; + return t.setup = function() { + for (var e = this.el_; e = e.previousElementSibling;) { + if (!(e instanceof HTMLElement)) throw new ReferenceError; + this.height_ += e.offsetHeight + } + this.update() + }, t.update = function(e) { + if (!e || "resize" !== e.type && "orientationchange" !== e.type) { + var t = window.pageYOffset >= this.height_; + t !== this.active_ && (this.header_.dataset.mdState = (this.active_ = t) ? "shadow" : "") + } else this.height_ = 0, this.setup() + }, t.reset = function() { + this.header_.dataset.mdState = "", this.height_ = 0, this.active_ = !1 + }, e + }(), + Title: function() { + function e(e, t) { + var n = "string" == typeof e ? document.querySelector(e) : e; + if (!(n instanceof HTMLElement)) throw new ReferenceError; + if (this.el_ = n, !((n = "string" == typeof t ? document.querySelector(t) : t) instanceof HTMLHeadingElement)) throw new ReferenceError; + this.header_ = n, this.active_ = !1 + } + var t = e.prototype; + return t.setup = function() { + var t = this; + Array.prototype.forEach.call(this.el_.children, function(e) { + e.style.width = t.el_.offsetWidth - 20 + "px" + }) + }, t.update = function(e) { + var t = this, + n = window.pageYOffset >= this.header_.offsetTop; + n !== this.active_ && (this.el_.dataset.mdState = (this.active_ = n) ? "active" : ""), "resize" !== e.type && "orientationchange" !== e.type || Array.prototype.forEach.call(this.el_.children, function(e) { + e.style.width = t.el_.offsetWidth - 20 + "px" + }) + }, t.reset = function() { + this.el_.dataset.mdState = "", this.el_.style.width = "", this.active_ = !1 + }, e + }() + }, + o = { + Blur: function() { + function e(e) { + this.els_ = "string" == typeof e ? document.querySelectorAll(e) : e, this.index_ = 0, this.offset_ = window.pageYOffset, this.dir_ = !1, this.anchors_ = [].reduce.call(this.els_, function(e, t) { + var n = decodeURIComponent(t.hash); + return e.concat(document.getElementById(n.substring(1)) || []) + }, []) + } + var t = e.prototype; + return t.setup = function() { + this.update() + }, t.update = function() { + var e = window.pageYOffset, + t = this.offset_ - e < 0; + if (this.dir_ !== t && (this.index_ = this.index_ = t ? 0 : this.els_.length - 1), 0 !== this.anchors_.length) { + if (this.offset_ <= e) + for (var n = this.index_ + 1; n < this.els_.length && this.anchors_[n].offsetTop - 80 <= e; n++) 0 < n && (this.els_[n - 1].dataset.mdState = "blur"), this.index_ = n; + else + for (var r = this.index_; 0 <= r; r--) { + if (!(this.anchors_[r].offsetTop - 80 > e)) { + this.index_ = r; + break + } + 0 < r && (this.els_[r - 1].dataset.mdState = "") + } + this.offset_ = e, this.dir_ = t + } + }, t.reset = function() { + Array.prototype.forEach.call(this.els_, function(e) { + e.dataset.mdState = "" + }), this.index_ = 0, this.offset_ = window.pageYOffset + }, e + }(), + Collapse: function() { + function e(e) { + var t = "string" == typeof e ? document.querySelector(e) : e; + if (!(t instanceof HTMLElement)) throw new ReferenceError; + this.el_ = t + } + var t = e.prototype; + return t.setup = function() { + var e = this.el_.getBoundingClientRect().height; + this.el_.style.display = e ? "block" : "none", this.el_.style.overflow = e ? "visible" : "hidden" + }, t.update = function() { + var e = this, + t = this.el_.getBoundingClientRect().height; + this.el_.style.display = "block", this.el_.style.overflow = ""; + var r = this.el_.previousElementSibling.previousElementSibling.checked; + if (r) this.el_.style.maxHeight = t + "px", requestAnimationFrame(function() { + e.el_.setAttribute("data-md-state", "animate"), e.el_.style.maxHeight = "0px" + }); + else { + this.el_.setAttribute("data-md-state", "expand"), this.el_.style.maxHeight = ""; + var n = this.el_.getBoundingClientRect().height; + this.el_.removeAttribute("data-md-state"), this.el_.style.maxHeight = "0px", requestAnimationFrame(function() { + e.el_.setAttribute("data-md-state", "animate"), e.el_.style.maxHeight = n + "px" + }) + } + this.el_.addEventListener("transitionend", function e(t) { + var n = t.target; + if (!(n instanceof HTMLElement)) throw new ReferenceError; + n.removeAttribute("data-md-state"), n.style.maxHeight = "", n.style.display = r ? "none" : "block", n.style.overflow = r ? "hidden" : "visible", n.removeEventListener("transitionend", e) + }, !1) + }, t.reset = function() { + this.el_.dataset.mdState = "", this.el_.style.maxHeight = "", this.el_.style.display = "", this.el_.style.overflow = "" + }, e + }(), + Scrolling: function() { + function e(e) { + var t = "string" == typeof e ? document.querySelector(e) : e; + if (!(t instanceof HTMLElement)) throw new ReferenceError; + this.el_ = t + } + var t = e.prototype; + return t.setup = function() { + this.el_.children[this.el_.children.length - 1].style.webkitOverflowScrolling = "touch"; + var e = this.el_.querySelectorAll("[data-md-toggle]"); + Array.prototype.forEach.call(e, function(e) { + if (!(e instanceof HTMLInputElement)) throw new ReferenceError; + if (e.checked) { + var t = e.nextElementSibling; + if (!(t instanceof HTMLElement)) throw new ReferenceError; + for (; + "NAV" !== t.tagName && t.nextElementSibling;) t = t.nextElementSibling; + if (!(e.parentNode instanceof HTMLElement && e.parentNode.parentNode instanceof HTMLElement)) throw new ReferenceError; + var n = e.parentNode.parentNode, + r = t.children[t.children.length - 1]; + n.style.webkitOverflowScrolling = "", r.style.webkitOverflowScrolling = "touch" + } + }) + }, t.update = function(e) { + var t = e.target; + if (!(t instanceof HTMLElement)) throw new ReferenceError; + var n = t.nextElementSibling; + if (!(n instanceof HTMLElement)) throw new ReferenceError; + for (; + "NAV" !== n.tagName && n.nextElementSibling;) n = n.nextElementSibling; + if (!(t.parentNode instanceof HTMLElement && t.parentNode.parentNode instanceof HTMLElement)) throw new ReferenceError; + var r = t.parentNode.parentNode, + i = n.children[n.children.length - 1]; + if (r.style.webkitOverflowScrolling = "", i.style.webkitOverflowScrolling = "", !t.checked) { + n.addEventListener("transitionend", function e() { + n instanceof HTMLElement && (r.style.webkitOverflowScrolling = "touch", n.removeEventListener("transitionend", e)) + }, !1) + } + if (t.checked) { + n.addEventListener("transitionend", function e() { + n instanceof HTMLElement && (i.style.webkitOverflowScrolling = "touch", n.removeEventListener("transitionend", e)) + }, !1) + } + }, t.reset = function() { + this.el_.children[1].style.webkitOverflowScrolling = ""; + var e = this.el_.querySelectorAll("[data-md-toggle]"); + Array.prototype.forEach.call(e, function(e) { + if (!(e instanceof HTMLInputElement)) throw new ReferenceError; + if (e.checked) { + var t = e.nextElementSibling; + if (!(t instanceof HTMLElement)) throw new ReferenceError; + for (; + "NAV" !== t.tagName && t.nextElementSibling;) t = t.nextElementSibling; + if (!(e.parentNode instanceof HTMLElement && e.parentNode.parentNode instanceof HTMLElement)) throw new ReferenceError; + var n = e.parentNode.parentNode, + r = t.children[t.children.length - 1]; + n.style.webkitOverflowScrolling = "", r.style.webkitOverflowScrolling = "" + } + }) + }, e + }() + }, + a = { + Lock: function() { + function e(e) { + var t = "string" == typeof e ? document.querySelector(e) : e; + if (!(t instanceof HTMLInputElement)) throw new ReferenceError; + if (this.el_ = t, !document.body) throw new ReferenceError; + this.lock_ = document.body + } + var t = e.prototype; + return t.setup = function() { + this.update() + }, t.update = function() { + var e = this; + this.el_.checked ? (this.offset_ = window.pageYOffset, setTimeout(function() { + window.scrollTo(0, 0), e.el_.checked && (e.lock_.dataset.mdState = "lock") + }, 400)) : (this.lock_.dataset.mdState = "", setTimeout(function() { + void 0 !== e.offset_ && window.scrollTo(0, e.offset_) + }, 100)) + }, t.reset = function() { + "lock" === this.lock_.dataset.mdState && window.scrollTo(0, this.offset_), this.lock_.dataset.mdState = "" + }, e + }(), + Result: n(9).a + }, + s = { + Position: function() { + function e(e, t) { + var n = "string" == typeof e ? document.querySelector(e) : e; + if (!(n instanceof HTMLElement && n.parentNode instanceof HTMLElement)) throw new ReferenceError; + if (this.el_ = n, this.parent_ = n.parentNode, !((n = "string" == typeof t ? document.querySelector(t) : t) instanceof HTMLElement)) throw new ReferenceError; + this.header_ = n, this.height_ = 0, this.pad_ = "fixed" === window.getComputedStyle(this.header_).position + } + var t = e.prototype; + return t.setup = function() { + var e = Array.prototype.reduce.call(this.parent_.children, function(e, t) { + return Math.max(e, t.offsetTop) + }, 0); + this.offset_ = e - (this.pad_ ? this.header_.offsetHeight : 0), this.update() + }, t.update = function(e) { + var t = window.pageYOffset, + n = window.innerHeight; + e && "resize" === e.type && this.setup(); + var r = this.pad_ ? this.header_.offsetHeight : 0, + i = this.parent_.offsetTop + this.parent_.offsetHeight, + o = n - r - Math.max(0, this.offset_ - t) - Math.max(0, t + n - i); + o !== this.height_ && (this.el_.style.height = (this.height_ = o) + "px"), t >= this.offset_ ? "lock" !== this.el_.dataset.mdState && (this.el_.dataset.mdState = "lock") : "lock" === this.el_.dataset.mdState && (this.el_.dataset.mdState = "") + }, t.reset = function() { + this.el_.dataset.mdState = "", this.el_.style.height = "", this.height_ = 0 + }, e + }() + }, + c = n(6), + l = n.n(c); + var u = { + Adapter: { + GitHub: function(o) { + var e, t; + + function n(e) { + var t; + t = o.call(this, e) || this; + var n = /^.+github\.com\/([^/]+)\/?([^/]+)?.*$/.exec(t.base_); + if (n && 3 === n.length) { + var r = n[1], + i = n[2]; + t.base_ = "https://api.github.com/users/" + r + "/repos", t.name_ = i + } + return t + } + return t = o, (e = n).prototype = Object.create(t.prototype), (e.prototype.constructor = e).__proto__ = t, n.prototype.fetch_ = function() { + var i = this; + return function n(r) { + return void 0 === r && (r = 0), fetch(i.base_ + "?per_page=30&page=" + r).then(function(e) { + return e.json() + }).then(function(e) { + if (!(e instanceof Array)) throw new TypeError; + if (i.name_) { + var t = e.find(function(e) { + return e.name === i.name_ + }); + return t || 30 !== e.length ? t ? [i.format_(t.stargazers_count) + " Stars", i.format_(t.forks_count) + " Forks"] : [] : n(r + 1) + } + return [e.length + " Repositories"] + }) + }() + }, n + }(function() { + function e(e) { + var t = "string" == typeof e ? document.querySelector(e) : e; + if (!(t instanceof HTMLAnchorElement)) throw new ReferenceError; + this.el_ = t, this.base_ = this.el_.href, this.salt_ = this.hash_(this.base_) + } + var t = e.prototype; + return t.fetch = function() { + var n = this; + return new Promise(function(t) { + var e = l.a.getJSON(n.salt_ + ".cache-source"); + void 0 !== e ? t(e) : n.fetch_().then(function(e) { + l.a.set(n.salt_ + ".cache-source", e, { + expires: 1 / 96 + }), t(e) + }) + }) + }, t.fetch_ = function() { + throw new Error("fetch_(): Not implemented") + }, t.format_ = function(e) { + return 1e4 < e ? (e / 1e3).toFixed(0) + "k" : 1e3 < e ? (e / 1e3).toFixed(1) + "k" : "" + e + }, t.hash_ = function(e) { + var t = 0; + if (0 === e.length) return t; + for (var n = 0, r = e.length; n < r; n++) t = (t << 5) - t + e.charCodeAt(n), t |= 0; + return t + }, e + }()) + }, + Repository: n(10).a + }, + f = { + Toggle: function() { + function e(e) { + var t = "string" == typeof e ? document.querySelector(e) : e; + if (!(t instanceof Node)) throw new ReferenceError; + this.el_ = t; + var n = document.querySelector("[data-md-component=header]"); + this.height_ = n.offsetHeight, this.active_ = !1 + } + var t = e.prototype; + return t.update = function() { + var e = window.pageYOffset >= this.el_.children[0].offsetTop + (5 - this.height_); + e !== this.active_ && (this.el_.dataset.mdState = (this.active_ = e) ? "hidden" : "") + }, t.reset = function() { + this.el_.dataset.mdState = "", this.active_ = !1 + }, e + }() + }; + t.a = { + Event: r, + Header: i, + Nav: o, + Search: a, + Sidebar: s, + Source: u, + Tabs: f + } +}, function(t, e, n) { + (function(e) { + t.exports = e.lunr = n(24) + }).call(this, n(4)) +}, function(e, f, d) { + "use strict"; + (function(t) { + var e = d(8), + n = setTimeout; + + function r() {} + + function o(e) { + if (!(this instanceof o)) throw new TypeError("Promises must be constructed via new"); + if ("function" != typeof e) throw new TypeError("not a function"); + this._state = 0, this._handled = !1, this._value = void 0, this._deferreds = [], u(e, this) + } + + function i(n, r) { + for (; 3 === n._state;) n = n._value; + 0 !== n._state ? (n._handled = !0, o._immediateFn(function() { + var e = 1 === n._state ? r.onFulfilled : r.onRejected; + if (null !== e) { + var t; + try { + t = e(n._value) + } catch (e) { + return void s(r.promise, e) + } + a(r.promise, t) + } else(1 === n._state ? a : s)(r.promise, n._value) + })) : n._deferreds.push(r) + } + + function a(t, e) { + try { + if (e === t) throw new TypeError("A promise cannot be resolved with itself."); + if (e && ("object" == typeof e || "function" == typeof e)) { + var n = e.then; + if (e instanceof o) return t._state = 3, t._value = e, void c(t); + if ("function" == typeof n) return void u((r = n, i = e, function() { + r.apply(i, arguments) + }), t) + } + t._state = 1, t._value = e, c(t) + } catch (e) { + s(t, e) + } + var r, i + } + + function s(e, t) { + e._state = 2, e._value = t, c(e) + } + + function c(e) { + 2 === e._state && 0 === e._deferreds.length && o._immediateFn(function() { + e._handled || o._unhandledRejectionFn(e._value) + }); + for (var t = 0, n = e._deferreds.length; t < n; t++) i(e, e._deferreds[t]); + e._deferreds = null + } + + function l(e, t, n) { + this.onFulfilled = "function" == typeof e ? e : null, this.onRejected = "function" == typeof t ? t : null, this.promise = n + } + + function u(e, t) { + var n = !1; + try { + e(function(e) { + n || (n = !0, a(t, e)) + }, function(e) { + n || (n = !0, s(t, e)) + }) + } catch (e) { + if (n) return; + n = !0, s(t, e) + } + } + o.prototype.catch = function(e) { + return this.then(null, e) + }, o.prototype.then = function(e, t) { + var n = new this.constructor(r); + return i(this, new l(e, t, n)), n + }, o.prototype.finally = e.a, o.all = function(t) { + return new o(function(r, i) { + if (!t || void 0 === t.length) throw new TypeError("Promise.all accepts an array"); + var o = Array.prototype.slice.call(t); + if (0 === o.length) return r([]); + var a = o.length; + + function s(t, e) { + try { + if (e && ("object" == typeof e || "function" == typeof e)) { + var n = e.then; + if ("function" == typeof n) return void n.call(e, function(e) { + s(t, e) + }, i) + } + o[t] = e, 0 == --a && r(o) + } catch (e) { + i(e) + } + } + for (var e = 0; e < o.length; e++) s(e, o[e]) + }) + }, o.resolve = function(t) { + return t && "object" == typeof t && t.constructor === o ? t : new o(function(e) { + e(t) + }) + }, o.reject = function(n) { + return new o(function(e, t) { + t(n) + }) + }, o.race = function(i) { + return new o(function(e, t) { + for (var n = 0, r = i.length; n < r; n++) i[n].then(e, t) + }) + }, o._immediateFn = "function" == typeof t && function(e) { + t(e) + } || function(e) { + n(e, 0) + }, o._unhandledRejectionFn = function(e) { + "undefined" != typeof console && console && console.warn("Possible Unhandled Promise Rejection:", e) + }, f.a = o + }).call(this, d(21).setImmediate) +}, function(e, t, n) { + "use strict"; + + function r(e, t) { + var n = document.createElement(e); + t && Array.prototype.forEach.call(Object.keys(t), function(e) { + n.setAttribute(e, t[e]) + }); + for (var r = arguments.length, i = new Array(2 < r ? r - 2 : 0), o = 2; o < r; o++) i[o - 2] = arguments[o]; + return function t(e) { + Array.prototype.forEach.call(e, function(e) { + "string" == typeof e || "number" == typeof e ? n.textContent += e : Array.isArray(e) ? t(e) : void 0 !== e.__html ? n.innerHTML += e.__html : e instanceof Node && n.appendChild(e) + }) + }(i), n + } + n.r(t), n.d(t, "createElement", function() { + return r + }) +}, function(e, t) { + var n; + n = function() { + return this + }(); + try { + n = n || new Function("return this")() + } catch (e) { + "object" == typeof window && (n = window) + } + e.exports = n +}, function(e, t, n) { + var r; + r = function() { + return function(n) { + var r = {}; + + function i(e) { + if (r[e]) return r[e].exports; + var t = r[e] = { + i: e, + l: !1, + exports: {} + }; + return n[e].call(t.exports, t, t.exports, i), t.l = !0, t.exports + } + return i.m = n, i.c = r, i.d = function(e, t, n) { + i.o(e, t) || Object.defineProperty(e, t, { + enumerable: !0, + get: n + }) + }, i.r = function(e) { + "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, { + value: "Module" + }), Object.defineProperty(e, "__esModule", { + value: !0 + }) + }, i.t = function(t, e) { + if (1 & e && (t = i(t)), 8 & e) return t; + if (4 & e && "object" == typeof t && t && t.__esModule) return t; + var n = Object.create(null); + if (i.r(n), Object.defineProperty(n, "default", { + enumerable: !0, + value: t + }), 2 & e && "string" != typeof t) + for (var r in t) i.d(n, r, function(e) { + return t[e] + }.bind(null, r)); + return n + }, i.n = function(e) { + var t = e && e.__esModule ? function() { + return e.default + } : function() { + return e + }; + return i.d(t, "a", t), t + }, i.o = function(e, t) { + return Object.prototype.hasOwnProperty.call(e, t) + }, i.p = "", i(i.s = 0) + }([function(e, t, n) { + "use strict"; + var i = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(e) { + return typeof e + } : function(e) { + return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e + }, + o = function() { + function r(e, t) { + for (var n = 0; n < t.length; n++) { + var r = t[n]; + r.enumerable = r.enumerable || !1, r.configurable = !0, "value" in r && (r.writable = !0), Object.defineProperty(e, r.key, r) + } + } + return function(e, t, n) { + return t && r(e.prototype, t), n && r(e, n), e + } + }(), + a = r(n(1)), + s = r(n(3)), + c = r(n(4)); + + function r(e) { + return e && e.__esModule ? e : { + default: e + } + } + var l = function(e) { + function r(e, t) { + ! function(e, t) { + if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") + }(this, r); + var n = function(e, t) { + if (!e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + return !t || "object" != typeof t && "function" != typeof t ? e : t + }(this, (r.__proto__ || Object.getPrototypeOf(r)).call(this)); + return n.resolveOptions(t), n.listenClick(e), n + } + return function(e, t) { + if ("function" != typeof t && null !== t) throw new TypeError("Super expression must either be null or a function, not " + typeof t); + e.prototype = Object.create(t && t.prototype, { + constructor: { + value: e, + enumerable: !1, + writable: !0, + configurable: !0 + } + }), t && (Object.setPrototypeOf ? Object.setPrototypeOf(e, t) : e.__proto__ = t) + }(r, s.default), o(r, [{ + key: "resolveOptions", + value: function() { + var e = 0 < arguments.length && void 0 !== arguments[0] ? arguments[0] : {}; + this.action = "function" == typeof e.action ? e.action : this.defaultAction, this.target = "function" == typeof e.target ? e.target : this.defaultTarget, this.text = "function" == typeof e.text ? e.text : this.defaultText, this.container = "object" === i(e.container) ? e.container : document.body + } + }, { + key: "listenClick", + value: function(e) { + var t = this; + this.listener = (0, c.default)(e, "click", function(e) { + return t.onClick(e) + }) + } + }, { + key: "onClick", + value: function(e) { + var t = e.delegateTarget || e.currentTarget; + this.clipboardAction && (this.clipboardAction = null), this.clipboardAction = new a.default({ + action: this.action(t), + target: this.target(t), + text: this.text(t), + container: this.container, + trigger: t, + emitter: this + }) + } + }, { + key: "defaultAction", + value: function(e) { + return u("action", e) + } + }, { + key: "defaultTarget", + value: function(e) { + var t = u("target", e); + if (t) return document.querySelector(t) + } + }, { + key: "defaultText", + value: function(e) { + return u("text", e) + } + }, { + key: "destroy", + value: function() { + this.listener.destroy(), this.clipboardAction && (this.clipboardAction.destroy(), this.clipboardAction = null) + } + }], [{ + key: "isSupported", + value: function() { + var e = 0 < arguments.length && void 0 !== arguments[0] ? arguments[0] : ["copy", "cut"], + t = "string" == typeof e ? [e] : e, + n = !!document.queryCommandSupported; + return t.forEach(function(e) { + n = n && !!document.queryCommandSupported(e) + }), n + } + }]), r + }(); + + function u(e, t) { + var n = "data-clipboard-" + e; + if (t.hasAttribute(n)) return t.getAttribute(n) + } + e.exports = l + }, function(e, t, n) { + "use strict"; + var r, i = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(e) { + return typeof e + } : function(e) { + return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e + }, + o = function() { + function r(e, t) { + for (var n = 0; n < t.length; n++) { + var r = t[n]; + r.enumerable = r.enumerable || !1, r.configurable = !0, "value" in r && (r.writable = !0), Object.defineProperty(e, r.key, r) + } + } + return function(e, t, n) { + return t && r(e.prototype, t), n && r(e, n), e + } + }(), + a = n(2), + s = (r = a) && r.__esModule ? r : { + default: r + }; + var c = function() { + function t(e) { + ! function(e, t) { + if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") + }(this, t), this.resolveOptions(e), this.initSelection() + } + return o(t, [{ + key: "resolveOptions", + value: function() { + var e = 0 < arguments.length && void 0 !== arguments[0] ? arguments[0] : {}; + this.action = e.action, this.container = e.container, this.emitter = e.emitter, this.target = e.target, this.text = e.text, this.trigger = e.trigger, this.selectedText = "" + } + }, { + key: "initSelection", + value: function() { + this.text ? this.selectFake() : this.target && this.selectTarget() + } + }, { + key: "selectFake", + value: function() { + var e = this, + t = "rtl" == document.documentElement.getAttribute("dir"); + this.removeFake(), this.fakeHandlerCallback = function() { + return e.removeFake() + }, this.fakeHandler = this.container.addEventListener("click", this.fakeHandlerCallback) || !0, this.fakeElem = document.createElement("textarea"), this.fakeElem.style.fontSize = "12pt", this.fakeElem.style.border = "0", this.fakeElem.style.padding = "0", this.fakeElem.style.margin = "0", this.fakeElem.style.position = "absolute", this.fakeElem.style[t ? "right" : "left"] = "-9999px"; + var n = window.pageYOffset || document.documentElement.scrollTop; + this.fakeElem.style.top = n + "px", this.fakeElem.setAttribute("readonly", ""), this.fakeElem.value = this.text, this.container.appendChild(this.fakeElem), this.selectedText = (0, s.default)(this.fakeElem), this.copyText() + } + }, { + key: "removeFake", + value: function() { + this.fakeHandler && (this.container.removeEventListener("click", this.fakeHandlerCallback), this.fakeHandler = null, this.fakeHandlerCallback = null), this.fakeElem && (this.container.removeChild(this.fakeElem), this.fakeElem = null) + } + }, { + key: "selectTarget", + value: function() { + this.selectedText = (0, s.default)(this.target), this.copyText() + } + }, { + key: "copyText", + value: function() { + var t = void 0; + try { + t = document.execCommand(this.action) + } catch (e) { + t = !1 + } + this.handleResult(t) + } + }, { + key: "handleResult", + value: function(e) { + this.emitter.emit(e ? "success" : "error", { + action: this.action, + text: this.selectedText, + trigger: this.trigger, + clearSelection: this.clearSelection.bind(this) + }) + } + }, { + key: "clearSelection", + value: function() { + this.trigger && this.trigger.focus(), window.getSelection().removeAllRanges() + } + }, { + key: "destroy", + value: function() { + this.removeFake() + } + }, { + key: "action", + set: function() { + var e = 0 < arguments.length && void 0 !== arguments[0] ? arguments[0] : "copy"; + if (this._action = e, "copy" !== this._action && "cut" !== this._action) throw new Error('Invalid "action" value, use either "copy" or "cut"') + }, + get: function() { + return this._action + } + }, { + key: "target", + set: function(e) { + if (void 0 !== e) { + if (!e || "object" !== (void 0 === e ? "undefined" : i(e)) || 1 !== e.nodeType) throw new Error('Invalid "target" value, use a valid Element'); + if ("copy" === this.action && e.hasAttribute("disabled")) throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute'); + if ("cut" === this.action && (e.hasAttribute("readonly") || e.hasAttribute("disabled"))) throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes'); + this._target = e + } + }, + get: function() { + return this._target + } + }]), t + }(); + e.exports = c + }, function(e, t) { + e.exports = function(e) { + var t; + if ("SELECT" === e.nodeName) e.focus(), t = e.value; + else if ("INPUT" === e.nodeName || "TEXTAREA" === e.nodeName) { + var n = e.hasAttribute("readonly"); + n || e.setAttribute("readonly", ""), e.select(), e.setSelectionRange(0, e.value.length), n || e.removeAttribute("readonly"), t = e.value + } else { + e.hasAttribute("contenteditable") && e.focus(); + var r = window.getSelection(), + i = document.createRange(); + i.selectNodeContents(e), r.removeAllRanges(), r.addRange(i), t = r.toString() + } + return t + } + }, function(e, t) { + function n() {} + n.prototype = { + on: function(e, t, n) { + var r = this.e || (this.e = {}); + return (r[e] || (r[e] = [])).push({ + fn: t, + ctx: n + }), this + }, + once: function(e, t, n) { + var r = this; + + function i() { + r.off(e, i), t.apply(n, arguments) + } + return i._ = t, this.on(e, i, n) + }, + emit: function(e) { + for (var t = [].slice.call(arguments, 1), n = ((this.e || (this.e = {}))[e] || []).slice(), r = 0, i = n.length; r < i; r++) n[r].fn.apply(n[r].ctx, t); + return this + }, + off: function(e, t) { + var n = this.e || (this.e = {}), + r = n[e], + i = []; + if (r && t) + for (var o = 0, a = r.length; o < a; o++) r[o].fn !== t && r[o].fn._ !== t && i.push(r[o]); + return i.length ? n[e] = i : delete n[e], this + } + }, e.exports = n + }, function(e, t, n) { + var d = n(5), + h = n(6); + e.exports = function(e, t, n) { + if (!e && !t && !n) throw new Error("Missing required arguments"); + if (!d.string(t)) throw new TypeError("Second argument must be a String"); + if (!d.fn(n)) throw new TypeError("Third argument must be a Function"); + if (d.node(e)) return u = t, f = n, (l = e).addEventListener(u, f), { + destroy: function() { + l.removeEventListener(u, f) + } + }; + if (d.nodeList(e)) return a = e, s = t, c = n, Array.prototype.forEach.call(a, function(e) { + e.addEventListener(s, c) + }), { + destroy: function() { + Array.prototype.forEach.call(a, function(e) { + e.removeEventListener(s, c) + }) + } + }; + if (d.string(e)) return r = e, i = t, o = n, h(document.body, r, i, o); + throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList"); + var r, i, o, a, s, c, l, u, f + } + }, function(e, n) { + n.node = function(e) { + return void 0 !== e && e instanceof HTMLElement && 1 === e.nodeType + }, n.nodeList = function(e) { + var t = Object.prototype.toString.call(e); + return void 0 !== e && ("[object NodeList]" === t || "[object HTMLCollection]" === t) && "length" in e && (0 === e.length || n.node(e[0])) + }, n.string = function(e) { + return "string" == typeof e || e instanceof String + }, n.fn = function(e) { + return "[object Function]" === Object.prototype.toString.call(e) + } + }, function(e, t, n) { + var a = n(7); + + function o(e, t, n, r, i) { + var o = function(t, n, e, r) { + return function(e) { + e.delegateTarget = a(e.target, n), e.delegateTarget && r.call(t, e) + } + }.apply(this, arguments); + return e.addEventListener(n, o, i), { + destroy: function() { + e.removeEventListener(n, o, i) + } + } + } + e.exports = function(e, t, n, r, i) { + return "function" == typeof e.addEventListener ? o.apply(null, arguments) : "function" == typeof n ? o.bind(null, document).apply(null, arguments) : ("string" == typeof e && (e = document.querySelectorAll(e)), Array.prototype.map.call(e, function(e) { + return o(e, t, n, r, i) + })) + } + }, function(e, t) { + if ("undefined" != typeof Element && !Element.prototype.matches) { + var n = Element.prototype; + n.matches = n.matchesSelector || n.mozMatchesSelector || n.msMatchesSelector || n.oMatchesSelector || n.webkitMatchesSelector + } + e.exports = function(e, t) { + for (; e && 9 !== e.nodeType;) { + if ("function" == typeof e.matches && e.matches(t)) return e; + e = e.parentNode + } + } + }]) + }, e.exports = r() +}, function(r, i, o) { + var a, s; + ! function(e) { + if (void 0 === (s = "function" == typeof(a = e) ? a.call(i, o, i, r) : a) || (r.exports = s), !0, r.exports = e(), !!0) { + var t = window.Cookies, + n = window.Cookies = e(); + n.noConflict = function() { + return window.Cookies = t, n + } + } + }(function() { + function m() { + for (var e = 0, t = {}; e < arguments.length; e++) { + var n = arguments[e]; + for (var r in n) t[r] = n[r] + } + return t + } + return function e(h) { + function p(e, t, n) { + var r; + if ("undefined" != typeof document) { + if (1 < arguments.length) { + if ("number" == typeof(n = m({ + path: "/" + }, p.defaults, n)).expires) { + var i = new Date; + i.setMilliseconds(i.getMilliseconds() + 864e5 * n.expires), n.expires = i + } + n.expires = n.expires ? n.expires.toUTCString() : ""; + try { + r = JSON.stringify(t), /^[\{\[]/.test(r) && (t = r) + } catch (e) {} + t = h.write ? h.write(t, e) : encodeURIComponent(String(t)).replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent), e = (e = (e = encodeURIComponent(String(e))).replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent)).replace(/[\(\)]/g, escape); + var o = ""; + for (var a in n) n[a] && (o += "; " + a, !0 !== n[a] && (o += "=" + n[a])); + return document.cookie = e + "=" + t + o + } + e || (r = {}); + for (var s = document.cookie ? document.cookie.split("; ") : [], c = /(%[0-9A-Z]{2})+/g, l = 0; l < s.length; l++) { + var u = s[l].split("="), + f = u.slice(1).join("="); + this.json || '"' !== f.charAt(0) || (f = f.slice(1, -1)); + try { + var d = u[0].replace(c, decodeURIComponent); + if (f = h.read ? h.read(f, d) : h(f, d) || f.replace(c, decodeURIComponent), this.json) try { + f = JSON.parse(f) + } catch (e) {} + if (e === d) { + r = f; + break + } + e || (r[d] = f) + } catch (e) {} + } + return r + } + } + return (p.set = p).get = function(e) { + return p.call(p, e) + }, p.getJSON = function() { + return p.apply({ + json: !0 + }, [].slice.call(arguments)) + }, p.defaults = {}, p.remove = function(e, t) { + p(e, "", m(t, { + expires: -1 + })) + }, p.withConverter = e, p + }(function() {}) + }) +}, function(e, t, n) { + "use strict"; + n.r(t); + var r = "function" == typeof fetch ? fetch.bind() : function(i, o) { + return o = o || {}, new Promise(function(e, t) { + var n = new XMLHttpRequest; + for (var r in n.open(o.method || "get", i, !0), o.headers) n.setRequestHeader(r, o.headers[r]); + + function s() { + var r, i = [], + o = [], + a = {}; + return n.getAllResponseHeaders().replace(/^(.*?):[^\S\n]*([\s\S]*?)$/gm, function(e, t, n) { + i.push(t = t.toLowerCase()), o.push([t, n]), r = a[t], a[t] = r ? r + "," + n : n + }), { + ok: 2 == (n.status / 100 | 0), + status: n.status, + statusText: n.statusText, + url: n.responseURL, + clone: s, + text: function() { + return Promise.resolve(n.responseText) + }, + json: function() { + return Promise.resolve(n.responseText).then(JSON.parse) + }, + blob: function() { + return Promise.resolve(new Blob([n.response])) + }, + headers: { + keys: function() { + return i + }, + entries: function() { + return o + }, + get: function(e) { + return a[e.toLowerCase()] + }, + has: function(e) { + return e.toLowerCase() in a + } + } + } + } + n.withCredentials = "include" == o.credentials, n.onload = function() { + e(s()) + }, n.onerror = t, n.send(o.body || null) + }) + }; + t.default = r +}, function(e, t, n) { + "use strict"; + t.a = function(t) { + var n = this.constructor; + return this.then(function(e) { + return n.resolve(t()).then(function() { + return e + }) + }, function(e) { + return n.resolve(t()).then(function() { + return n.reject(e) + }) + }) + } +}, function(e, n, r) { + "use strict"; + (function(f) { + r.d(n, "a", function() { + return t + }); + var e = r(1), + d = r.n(e), + h = function(e) { + var t = document.getElementsByName("lang:" + e)[0]; + if (!(t instanceof HTMLMetaElement)) throw new ReferenceError; + return t.content + }, + t = function() { + function e(e, t) { + var n = "string" == typeof e ? document.querySelector(e) : e; + if (!(n instanceof HTMLElement)) throw new ReferenceError; + this.el_ = n; + var r = Array.prototype.slice.call(this.el_.children), + i = r[0], + o = r[1]; + this.data_ = t, this.meta_ = i, this.list_ = o, this.message_ = { + placeholder: this.meta_.textContent, + none: h("search.result.none"), + one: h("search.result.one"), + other: h("search.result.other") + }; + var a = h("search.tokenizer"); + a.length && (d.a.tokenizer.separator = a), this.lang_ = h("search.language").split(",").filter(Boolean).map(function(e) { + return e.trim() + }) + } + return e.prototype.update = function(e) { + var t, a = this; + if ("focus" !== e.type || this.index_) { + if ("focus" === e.type || "keyup" === e.type) { + var n = e.target; + if (!(n instanceof HTMLInputElement)) throw new ReferenceError; + if (!this.index_ || n.value === this.value_) return; + for (; this.list_.firstChild;) this.list_.removeChild(this.list_.firstChild); + if (this.value_ = n.value, 0 === this.value_.length) return void(this.meta_.textContent = this.message_.placeholder); + var r = this.index_.query(function(t) { + a.value_.toLowerCase().split(" ").filter(Boolean).forEach(function(e) { + t.term(e, { + wildcard: d.a.Query.wildcard.TRAILING + }) + }) + }).reduce(function(e, t) { + var n = a.docs_.get(t.ref); + if (n.parent) { + var r = n.parent.location; + e.set(r, (e.get(r) || []).concat(t)) + } else { + var i = n.location; + e.set(i, e.get(i) || []) + } + return e + }, new Map), + i = (t = this.value_.trim(), t.replace(/[|\\{}()[\]^$+*?.-]/g, "\\$&")).replace(new RegExp(d.a.tokenizer.separator, "img"), "|"), + s = new RegExp("(^|" + d.a.tokenizer.separator + ")(" + i + ")", "img"), + c = function(e, t, n) { + return t + "" + n + "" + }; + this.stack_ = [], r.forEach(function(e, t) { + var n, r = a.docs_.get(t), + i = f.createElement("li", { + class: "md-search-result__item" + }, f.createElement("a", { + href: r.location, + title: r.title, + class: "md-search-result__link", + tabindex: "-1" + }, f.createElement("article", { + class: "md-search-result__article md-search-result__article--document" + }, f.createElement("h1", { + class: "md-search-result__title" + }, { + __html: r.title.replace(s, c) + }), r.text.length ? f.createElement("p", { + class: "md-search-result__teaser" + }, { + __html: r.text.replace(s, c) + }) : {}))), + o = e.map(function(t) { + return function() { + var e = a.docs_.get(t.ref); + i.appendChild(f.createElement("a", { + href: e.location, + title: e.title, + class: "md-search-result__link", + "data-md-rel": "anchor", + tabindex: "-1" + }, f.createElement("article", { + class: "md-search-result__article" + }, f.createElement("h1", { + class: "md-search-result__title" + }, { + __html: e.title.replace(s, c) + }), e.text.length ? f.createElement("p", { + class: "md-search-result__teaser" + }, { + __html: function(e, t) { + var n = t; + if (e.length > n) { + for (; + " " !== e[n] && 0 < --n;); + return e.substring(0, n) + "..." + } + return e + }(e.text.replace(s, c), 400) + }) : {}))) + } + }); + (n = a.stack_).push.apply(n, [function() { + return a.list_.appendChild(i) + }].concat(o)) + }); + var o = this.el_.parentNode; + if (!(o instanceof HTMLElement)) throw new ReferenceError; + for (; this.stack_.length && o.offsetHeight >= o.scrollHeight - 16;) this.stack_.shift()(); + var l = this.list_.querySelectorAll("[data-md-rel=anchor]"); + switch (Array.prototype.forEach.call(l, function(r) { + ["click", "keydown"].forEach(function(n) { + r.addEventListener(n, function(e) { + if ("keydown" !== n || 13 === e.keyCode) { + var t = document.querySelector("[data-md-toggle=search]"); + if (!(t instanceof HTMLInputElement)) throw new ReferenceError; + t.checked && (t.checked = !1, t.dispatchEvent(new CustomEvent("change"))), e.preventDefault(), setTimeout(function() { + document.location.href = r.href + }, 100) + } + }) + }) + }), r.size) { + case 0: + this.meta_.textContent = this.message_.none; + break; + case 1: + this.meta_.textContent = this.message_.one; + break; + default: + this.meta_.textContent = this.message_.other.replace("#", r.size) + } + } + } else { + var u = function(e) { + a.docs_ = e.reduce(function(e, t) { + var n, r, i, o = t.location.split("#"), + a = o[0], + s = o[1]; + return t.text = (n = t.text, r = document.createTextNode(n), (i = document.createElement("p")).appendChild(r), i.innerHTML), s && (t.parent = e.get(a), t.parent && !t.parent.done && (t.parent.title = t.title, t.parent.text = t.text, t.parent.done = !0)), t.text = t.text.replace(/\n/g, " ").replace(/\s+/g, " ").replace(/\s+([,.:;!?])/g, function(e, t) { + return t + }), t.parent && t.parent.title === t.title || e.set(t.location, t), e + }, new Map); + var i = a.docs_, + o = a.lang_; + a.stack_ = [], a.index_ = d()(function() { + var e, t = this, + n = { + "search.pipeline.trimmer": d.a.trimmer, + "search.pipeline.stopwords": d.a.stopWordFilter + }, + r = Object.keys(n).reduce(function(e, t) { + return h(t).match(/^false$/i) || e.push(n[t]), e + }, []); + this.pipeline.reset(), r && (e = this.pipeline).add.apply(e, r), 1 === o.length && "en" !== o[0] && d.a[o[0]] ? this.use(d.a[o[0]]) : 1 < o.length && this.use(d.a.multiLanguage.apply(d.a, o)), this.field("title", { + boost: 10 + }), this.field("text"), this.ref("location"), i.forEach(function(e) { + return t.add(e) + }) + }); + var t = a.el_.parentNode; + if (!(t instanceof HTMLElement)) throw new ReferenceError; + t.addEventListener("scroll", function() { + for (; a.stack_.length && t.scrollTop + t.offsetHeight >= t.scrollHeight - 16;) a.stack_.splice(0, 10).forEach(function(e) { + return e() + }) + }) + }; + setTimeout(function() { + return "function" == typeof a.data_ ? a.data_().then(u) : u(a.data_) + }, 250) + } + }, e + }() + }).call(this, r(3)) +}, function(e, n, r) { + "use strict"; + (function(t) { + r.d(n, "a", function() { + return e + }); + var e = function() { + function e(e) { + var t = "string" == typeof e ? document.querySelector(e) : e; + if (!(t instanceof HTMLElement)) throw new ReferenceError; + this.el_ = t + } + return e.prototype.initialize = function(e) { + e.length && this.el_.children.length && this.el_.children[this.el_.children.length - 1].appendChild(t.createElement("ul", { + class: "md-source__facts" + }, e.map(function(e) { + return t.createElement("li", { + class: "md-source__fact" + }, e) + }))), this.el_.dataset.mdState = "done" + }, e + }() + }).call(this, r(3)) +}, , , function(e, n, c) { + "use strict"; + c.r(n), + function(o) { + c.d(n, "app", function() { + return t + }); + c(14), c(15), c(16), c(17), c(18), c(19), c(20); + var r = c(2), + e = c(5), + a = c.n(e), + i = c(0); + window.Promise = window.Promise || r.a; + var s = function(e) { + var t = document.getElementsByName("lang:" + e)[0]; + if (!(t instanceof HTMLMetaElement)) throw new ReferenceError; + return t.content + }; + var t = { + initialize: function(t) { + new i.a.Event.Listener(document, "DOMContentLoaded", function() { + if (!(document.body instanceof HTMLElement)) throw new ReferenceError; + Modernizr.addTest("ios", function() { + return !!navigator.userAgent.match(/(iPad|iPhone|iPod)/g) + }); + var e = document.querySelectorAll("table:not([class])"); + if (Array.prototype.forEach.call(e, function(e) { + var t = o.createElement("div", { + class: "md-typeset__scrollwrap" + }, o.createElement("div", { + class: "md-typeset__table" + })); + e.nextSibling ? e.parentNode.insertBefore(t, e.nextSibling) : e.parentNode.appendChild(t), t.children[0].appendChild(e) + }), a.a.isSupported()) { + var t = document.querySelectorAll(".codehilite > pre, pre > code"); + Array.prototype.forEach.call(t, function(e, t) { + var n = "__code_" + t, + r = o.createElement("button", { + class: "md-clipboard", + title: s("clipboard.copy"), + "data-clipboard-target": "#" + n + " pre, #" + n + " code" + }, o.createElement("span", { + class: "md-clipboard__message" + })), + i = e.parentNode; + i.id = n, i.insertBefore(r, e) + }), new a.a(".md-clipboard").on("success", function(e) { + var t = e.trigger.querySelector(".md-clipboard__message"); + if (!(t instanceof HTMLElement)) throw new ReferenceError; + e.clearSelection(), t.dataset.mdTimer && clearTimeout(parseInt(t.dataset.mdTimer, 10)), t.classList.add("md-clipboard__message--active"), t.innerHTML = s("clipboard.copied"), t.dataset.mdTimer = setTimeout(function() { + t.classList.remove("md-clipboard__message--active"), t.dataset.mdTimer = "" + }, 2e3).toString() + }) + } + if (!Modernizr.details) { + var n = document.querySelectorAll("details > summary"); + Array.prototype.forEach.call(n, function(e) { + e.addEventListener("click", function(e) { + var t = e.target.parentNode; + t.hasAttribute("open") ? t.removeAttribute("open") : t.setAttribute("open", "") + }) + }) + } + var r = function() { + if (document.location.hash) { + var e = document.getElementById(document.location.hash.substring(1)); + if (!e) return; + for (var t = e.parentNode; t && !(t instanceof HTMLDetailsElement);) t = t.parentNode; + if (t && !t.open) { + t.open = !0; + var n = location.hash; + location.hash = " ", location.hash = n + } + } + }; + if (window.addEventListener("hashchange", r), r(), Modernizr.ios) { + var i = document.querySelectorAll("[data-md-scrollfix]"); + Array.prototype.forEach.call(i, function(t) { + t.addEventListener("touchstart", function() { + var e = t.scrollTop; + 0 === e ? t.scrollTop = 1 : e + t.offsetHeight === t.scrollHeight && (t.scrollTop = e - 1) + }) + }) + } + }).listen(), new i.a.Event.Listener(window, ["scroll", "resize", "orientationchange"], new i.a.Header.Shadow("[data-md-component=container]", "[data-md-component=header]")).listen(), new i.a.Event.Listener(window, ["scroll", "resize", "orientationchange"], new i.a.Header.Title("[data-md-component=title]", ".md-typeset h1")).listen(), document.querySelector("[data-md-component=hero]") && new i.a.Event.Listener(window, ["scroll", "resize", "orientationchange"], new i.a.Tabs.Toggle("[data-md-component=hero]")).listen(), document.querySelector("[data-md-component=tabs]") && new i.a.Event.Listener(window, ["scroll", "resize", "orientationchange"], new i.a.Tabs.Toggle("[data-md-component=tabs]")).listen(), new i.a.Event.MatchMedia("(min-width: 1220px)", new i.a.Event.Listener(window, ["scroll", "resize", "orientationchange"], new i.a.Sidebar.Position("[data-md-component=navigation]", "[data-md-component=header]"))), document.querySelector("[data-md-component=toc]") && new i.a.Event.MatchMedia("(min-width: 960px)", new i.a.Event.Listener(window, ["scroll", "resize", "orientationchange"], new i.a.Sidebar.Position("[data-md-component=toc]", "[data-md-component=header]"))), new i.a.Event.MatchMedia("(min-width: 960px)", new i.a.Event.Listener(window, "scroll", new i.a.Nav.Blur("[data-md-component=toc] .md-nav__link"))); + var e = document.querySelectorAll("[data-md-component=collapsible]"); + Array.prototype.forEach.call(e, function(e) { + new i.a.Event.MatchMedia("(min-width: 1220px)", new i.a.Event.Listener(e.previousElementSibling, "click", new i.a.Nav.Collapse(e))) + }), new i.a.Event.MatchMedia("(max-width: 1219px)", new i.a.Event.Listener("[data-md-component=navigation] [data-md-toggle]", "change", new i.a.Nav.Scrolling("[data-md-component=navigation] nav"))), document.querySelector("[data-md-component=search]") && (new i.a.Event.MatchMedia("(max-width: 959px)", new i.a.Event.Listener("[data-md-toggle=search]", "change", new i.a.Search.Lock("[data-md-toggle=search]")))), + new i.a.Event.Listener(document.body, "keydown", function(e) { + if (9 === e.keyCode) { + var t = document.querySelectorAll("[data-md-component=navigation] .md-nav__link[for]:not([tabindex])"); + Array.prototype.forEach.call(t, function(e) { + e.offsetHeight && (e.tabIndex = 0) + }) + } + }).listen(), new i.a.Event.Listener(document.body, "mousedown", function() { + var e = document.querySelectorAll("[data-md-component=navigation] .md-nav__link[tabindex]"); + Array.prototype.forEach.call(e, function(e) { + e.removeAttribute("tabIndex") + }) + }).listen(), document.body.addEventListener("click", function() { + "tabbing" === document.body.dataset.mdState && (document.body.dataset.mdState = "") + }), new i.a.Event.MatchMedia("(max-width: 959px)", new i.a.Event.Listener("[data-md-component=navigation] [href^='#']", "click", function() { + var e = document.querySelector("[data-md-toggle=drawer]"); + if (!(e instanceof HTMLInputElement)) throw new ReferenceError; + e.checked && (e.checked = !1, e.dispatchEvent(new CustomEvent("change"))) + })), + function() { + var e = document.querySelector("[data-md-source]"); + if (!e) return r.a.resolve([]); + if (!(e instanceof HTMLAnchorElement)) throw new ReferenceError; + switch (e.dataset.mdSource) { + case "github": + return new i.a.Source.Adapter.GitHub(e).fetch(); + default: + return r.a.resolve([]) + } + }().then(function(t) { + var e = document.querySelectorAll("[data-md-source]"); + Array.prototype.forEach.call(e, function(e) { + new i.a.Source.Repository(e).initialize(t) + }) + }); + var n = function() { + var e = document.querySelectorAll("details"); + Array.prototype.forEach.call(e, function(e) { + e.setAttribute("open", "") + }) + }; + new i.a.Event.MatchMedia("print", { + listen: n, + unlisten: function() {} + }), window.onbeforeprint = n + } + } + }.call(this, c(3)) +}, function(e, t, n) { + e.exports = n.p + "assets/images/icons/bitbucket.1b09e088.svg" +}, function(e, t, n) { + e.exports = n.p + "assets/images/icons/github.f0b8504a.svg" +}, function(e, t, n) { + e.exports = n.p + "assets/images/icons/gitlab.6dd19c00.svg" +}, function(e, t) { + e.exports = "/Users/squidfunk/Desktop/General/Sources/mkdocs-material/material/application.4031d38b.css" +}, function(e, t) { + e.exports = "/Users/squidfunk/Desktop/General/Sources/mkdocs-material/material/application-palette.224b79ff.css" +}, function(e, t) { + ! function() { + if ("undefined" != typeof window) try { + var e = new window.CustomEvent("test", { + cancelable: !0 + }); + if (e.preventDefault(), !0 !== e.defaultPrevented) throw new Error("Could not prevent default") + } catch (e) { + var t = function(e, t) { + var n, r; + return (t = t || {}).bubbles = !!t.bubbles, t.cancelable = !!t.cancelable, (n = document.createEvent("CustomEvent")).initCustomEvent(e, t.bubbles, t.cancelable, t.detail), r = n.preventDefault, n.preventDefault = function() { + r.call(this); + try { + Object.defineProperty(this, "defaultPrevented", { + get: function() { + return !0 + } + }) + } catch (e) { + this.defaultPrevented = !0 + } + }, n + }; + t.prototype = window.Event.prototype, window.CustomEvent = t + } + }() +}, function(e, t, n) { + window.fetch || (window.fetch = n(7).default || n(7)) +}, function(e, i, o) { + (function(e) { + var t = void 0 !== e && e || "undefined" != typeof self && self || window, + n = Function.prototype.apply; + + function r(e, t) { + this._id = e, this._clearFn = t + } + i.setTimeout = function() { + return new r(n.call(setTimeout, t, arguments), clearTimeout) + }, i.setInterval = function() { + return new r(n.call(setInterval, t, arguments), clearInterval) + }, i.clearTimeout = i.clearInterval = function(e) { + e && e.close() + }, r.prototype.unref = r.prototype.ref = function() {}, r.prototype.close = function() { + this._clearFn.call(t, this._id) + }, i.enroll = function(e, t) { + clearTimeout(e._idleTimeoutId), e._idleTimeout = t + }, i.unenroll = function(e) { + clearTimeout(e._idleTimeoutId), e._idleTimeout = -1 + }, i._unrefActive = i.active = function(e) { + clearTimeout(e._idleTimeoutId); + var t = e._idleTimeout; + 0 <= t && (e._idleTimeoutId = setTimeout(function() { + e._onTimeout && e._onTimeout() + }, t)) + }, o(22), i.setImmediate = "undefined" != typeof self && self.setImmediate || void 0 !== e && e.setImmediate || this && this.setImmediate, i.clearImmediate = "undefined" != typeof self && self.clearImmediate || void 0 !== e && e.clearImmediate || this && this.clearImmediate + }).call(this, o(4)) +}, function(e, t, n) { + (function(e, p) { + ! function(n, r) { + "use strict"; + if (!n.setImmediate) { + var i, o, t, a, e, s = 1, + c = {}, + l = !1, + u = n.document, + f = Object.getPrototypeOf && Object.getPrototypeOf(n); + f = f && f.setTimeout ? f : n, i = "[object process]" === {}.toString.call(n.process) ? function(e) { + p.nextTick(function() { + h(e) + }) + } : function() { + if (n.postMessage && !n.importScripts) { + var e = !0, + t = n.onmessage; + return n.onmessage = function() { + e = !1 + }, n.postMessage("", "*"), n.onmessage = t, e + } + }() ? (a = "setImmediate$" + Math.random() + "$", e = function(e) { + e.source === n && "string" == typeof e.data && 0 === e.data.indexOf(a) && h(+e.data.slice(a.length)) + }, n.addEventListener ? n.addEventListener("message", e, !1) : n.attachEvent("onmessage", e), function(e) { + n.postMessage(a + e, "*") + }) : n.MessageChannel ? ((t = new MessageChannel).port1.onmessage = function(e) { + h(e.data) + }, function(e) { + t.port2.postMessage(e) + }) : u && "onreadystatechange" in u.createElement("script") ? (o = u.documentElement, function(e) { + var t = u.createElement("script"); + t.onreadystatechange = function() { + h(e), t.onreadystatechange = null, o.removeChild(t), t = null + }, o.appendChild(t) + }) : function(e) { + setTimeout(h, 0, e) + }, f.setImmediate = function(e) { + "function" != typeof e && (e = new Function("" + e)); + for (var t = new Array(arguments.length - 1), n = 0; n < t.length; n++) t[n] = arguments[n + 1]; + var r = { + callback: e, + args: t + }; + return c[s] = r, i(s), s++ + }, f.clearImmediate = d + } + + function d(e) { + delete c[e] + } + + function h(e) { + if (l) setTimeout(h, 0, e); + else { + var t = c[e]; + if (t) { + l = !0; + try { + ! function(e) { + var t = e.callback, + n = e.args; + switch (n.length) { + case 0: + t(); + break; + case 1: + t(n[0]); + break; + case 2: + t(n[0], n[1]); + break; + case 3: + t(n[0], n[1], n[2]); + break; + default: + t.apply(r, n) + } + }(t) + } finally { + d(e), l = !1 + } + } + } + } + }("undefined" == typeof self ? void 0 === e ? this : e : self) + }).call(this, n(4), n(23)) +}, function(e, t) { + var n, r, i = e.exports = {}; + + function o() { + throw new Error("setTimeout has not been defined") + } + + function a() { + throw new Error("clearTimeout has not been defined") + } + + function s(t) { + if (n === setTimeout) return setTimeout(t, 0); + if ((n === o || !n) && setTimeout) return n = setTimeout, setTimeout(t, 0); + try { + return n(t, 0) + } catch (e) { + try { + return n.call(null, t, 0) + } catch (e) { + return n.call(this, t, 0) + } + } + }! function() { + try { + n = "function" == typeof setTimeout ? setTimeout : o + } catch (e) { + n = o + } + try { + r = "function" == typeof clearTimeout ? clearTimeout : a + } catch (e) { + r = a + } + }(); + var c, l = [], + u = !1, + f = -1; + + function d() { + u && c && (u = !1, c.length ? l = c.concat(l) : f = -1, l.length && h()) + } + + function h() { + if (!u) { + var e = s(d); + u = !0; + for (var t = l.length; t;) { + for (c = l, l = []; ++f < t;) c && c[f].run(); + f = -1, t = l.length + } + c = null, u = !1, + function(t) { + if (r === clearTimeout) return clearTimeout(t); + if ((r === a || !r) && clearTimeout) return r = clearTimeout, clearTimeout(t); + try { + r(t) + } catch (e) { + try { + return r.call(null, t) + } catch (e) { + return r.call(this, t) + } + } + }(e) + } + } + + function p(e, t) { + this.fun = e, this.array = t + } + + function m() {} + i.nextTick = function(e) { + var t = new Array(arguments.length - 1); + if (1 < arguments.length) + for (var n = 1; n < arguments.length; n++) t[n - 1] = arguments[n]; + l.push(new p(e, t)), 1 !== l.length || u || s(h) + }, p.prototype.run = function() { + this.fun.apply(null, this.array) + }, i.title = "browser", i.browser = !0, i.env = {}, i.argv = [], i.version = "", i.versions = {}, i.on = m, i.addListener = m, i.once = m, i.off = m, i.removeListener = m, i.removeAllListeners = m, i.emit = m, i.prependListener = m, i.prependOnceListener = m, i.listeners = function(e) { + return [] + }, i.binding = function(e) { + throw new Error("process.binding is not supported") + }, i.cwd = function() { + return "/" + }, i.chdir = function(e) { + throw new Error("process.chdir is not supported") + }, i.umask = function() { + return 0 + } +}, function(i, o, a) { + var s, c; + /** + * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 2.3.6 + * Copyright (C) 2019 Oliver Nightingale + * @license MIT + */ + ! function() { + var t, l, u, e, n, f, d, h, p, m, y, v, g, w, _, E, x, b, k, S, T, L, R, O, C, r, D = function(e) { + var t = new D.Builder; + return t.pipeline.add(D.trimmer, D.stopWordFilter, D.stemmer), t.searchPipeline.add(D.stemmer), e.call(t, t), t.build() + }; + D.version = "2.3.6", D.utils = {}, D.utils.warn = (t = this, function(e) { + t.console && console.warn && console.warn(e) + }), D.utils.asString = function(e) { + return null == e ? "" : e.toString() + }, D.utils.clone = function(e) { + if (null == e) return e; + for (var t = Object.create(null), n = Object.keys(e), r = 0; r < n.length; r++) { + var i = n[r], + o = e[i]; + if (Array.isArray(o)) t[i] = o.slice(); + else { + if ("string" != typeof o && "number" != typeof o && "boolean" != typeof o) throw new TypeError("clone is not deep and does not support nested objects"); + t[i] = o + } + } + return t + }, D.FieldRef = function(e, t, n) { + this.docRef = e, this.fieldName = t, this._stringValue = n + }, D.FieldRef.joiner = "/", D.FieldRef.fromString = function(e) { + var t = e.indexOf(D.FieldRef.joiner); + if (-1 === t) throw "malformed field ref string"; + var n = e.slice(0, t), + r = e.slice(t + 1); + return new D.FieldRef(r, n, e) + }, D.FieldRef.prototype.toString = function() { + return null == this._stringValue && (this._stringValue = this.fieldName + D.FieldRef.joiner + this.docRef), this._stringValue + }, D.Set = function(e) { + if (this.elements = Object.create(null), e) { + this.length = e.length; + for (var t = 0; t < this.length; t++) this.elements[e[t]] = !0 + } else this.length = 0 + }, D.Set.complete = { + intersect: function(e) { + return e + }, + union: function(e) { + return e + }, + contains: function() { + return !0 + } + }, D.Set.empty = { + intersect: function() { + return this + }, + union: function(e) { + return e + }, + contains: function() { + return !1 + } + }, D.Set.prototype.contains = function(e) { + return !!this.elements[e] + }, D.Set.prototype.intersect = function(e) { + var t, n, r, i = []; + if (e === D.Set.complete) return this; + if (e === D.Set.empty) return e; + n = this.length < e.length ? (t = this, e) : (t = e, this), r = Object.keys(t.elements); + for (var o = 0; o < r.length; o++) { + var a = r[o]; + a in n.elements && i.push(a) + } + return new D.Set(i) + }, D.Set.prototype.union = function(e) { + return e === D.Set.complete ? D.Set.complete : e === D.Set.empty ? this : new D.Set(Object.keys(this.elements).concat(Object.keys(e.elements))) + }, D.idf = function(e, t) { + var n = 0; + for (var r in e) "_index" != r && (n += Object.keys(e[r]).length); + var i = (t - n + .5) / (n + .5); + return Math.log(1 + Math.abs(i)) + }, D.Token = function(e, t) { + this.str = e || "", this.metadata = t || {} + }, D.Token.prototype.toString = function() { + return this.str + }, D.Token.prototype.update = function(e) { + return this.str = e(this.str, this.metadata), this + }, D.Token.prototype.clone = function(e) { + return e = e || function(e) { + return e + }, new D.Token(e(this.str, this.metadata), this.metadata) + }, D.tokenizer = function(e, t) { + if (null == e || null == e) return []; + if (Array.isArray(e)) return e.map(function(e) { + return new D.Token(D.utils.asString(e).toLowerCase(), D.utils.clone(t)) + }); + for (var n = e.toString().trim().toLowerCase(), r = n.length, i = [], o = 0, a = 0; o <= r; o++) { + var s = o - a; + if (n.charAt(o).match(D.tokenizer.separator) || o == r) { + if (0 < s) { + var c = D.utils.clone(t) || {}; + c.position = [a, s], c.index = i.length, i.push(new D.Token(n.slice(a, o), c)) + } + a = o + 1 + } + } + return i + }, D.tokenizer.separator = /[\s\-]+/, D.Pipeline = function() { + this._stack = [] + }, D.Pipeline.registeredFunctions = Object.create(null), D.Pipeline.registerFunction = function(e, t) { + t in this.registeredFunctions && D.utils.warn("Overwriting existing registered function: " + t), e.label = t, D.Pipeline.registeredFunctions[e.label] = e + }, D.Pipeline.warnIfFunctionNotRegistered = function(e) { + e.label && e.label in this.registeredFunctions || D.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n", e) + }, D.Pipeline.load = function(e) { + var n = new D.Pipeline; + return e.forEach(function(e) { + var t = D.Pipeline.registeredFunctions[e]; + if (!t) throw new Error("Cannot load unregistered function: " + e); + n.add(t) + }), n + }, D.Pipeline.prototype.add = function() { + Array.prototype.slice.call(arguments).forEach(function(e) { + D.Pipeline.warnIfFunctionNotRegistered(e), this._stack.push(e) + }, this) + }, D.Pipeline.prototype.after = function(e, t) { + D.Pipeline.warnIfFunctionNotRegistered(t); + var n = this._stack.indexOf(e); + if (-1 == n) throw new Error("Cannot find existingFn"); + n += 1, this._stack.splice(n, 0, t) + }, D.Pipeline.prototype.before = function(e, t) { + D.Pipeline.warnIfFunctionNotRegistered(t); + var n = this._stack.indexOf(e); + if (-1 == n) throw new Error("Cannot find existingFn"); + this._stack.splice(n, 0, t) + }, D.Pipeline.prototype.remove = function(e) { + var t = this._stack.indexOf(e); - 1 != t && this._stack.splice(t, 1) + }, D.Pipeline.prototype.run = function(e) { + for (var t = this._stack.length, n = 0; n < t; n++) { + for (var r = this._stack[n], i = [], o = 0; o < e.length; o++) { + var a = r(e[o], o, e); + if (void 0 !== a && "" !== a) + if (Array.isArray(a)) + for (var s = 0; s < a.length; s++) i.push(a[s]); + else i.push(a) + } + e = i + } + return e + }, D.Pipeline.prototype.runString = function(e, t) { + var n = new D.Token(e, t); + return this.run([n]).map(function(e) { + return e.toString() + }) + }, D.Pipeline.prototype.reset = function() { + this._stack = [] + }, D.Pipeline.prototype.toJSON = function() { + return this._stack.map(function(e) { + return D.Pipeline.warnIfFunctionNotRegistered(e), e.label + }) + }, D.Vector = function(e) { + this._magnitude = 0, this.elements = e || [] + }, D.Vector.prototype.positionForIndex = function(e) { + if (0 == this.elements.length) return 0; + for (var t = 0, n = this.elements.length / 2, r = n - t, i = Math.floor(r / 2), o = this.elements[2 * i]; 1 < r && (o < e && (t = i), e < o && (n = i), o != e);) r = n - t, i = t + Math.floor(r / 2), o = this.elements[2 * i]; + return o == e ? 2 * i : e < o ? 2 * i : o < e ? 2 * (i + 1) : void 0 + }, D.Vector.prototype.insert = function(e, t) { + this.upsert(e, t, function() { + throw "duplicate index" + }) + }, D.Vector.prototype.upsert = function(e, t, n) { + this._magnitude = 0; + var r = this.positionForIndex(e); + this.elements[r] == e ? this.elements[r + 1] = n(this.elements[r + 1], t) : this.elements.splice(r, 0, e, t) + }, D.Vector.prototype.magnitude = function() { + if (this._magnitude) return this._magnitude; + for (var e = 0, t = this.elements.length, n = 1; n < t; n += 2) { + var r = this.elements[n]; + e += r * r + } + return this._magnitude = Math.sqrt(e) + }, D.Vector.prototype.dot = function(e) { + for (var t = 0, n = this.elements, r = e.elements, i = n.length, o = r.length, a = 0, s = 0, c = 0, l = 0; c < i && l < o;)(a = n[c]) < (s = r[l]) ? c += 2 : s < a ? l += 2 : a == s && (t += n[c + 1] * r[l + 1], c += 2, l += 2); + return t + }, D.Vector.prototype.similarity = function(e) { + return this.dot(e) / this.magnitude() || 0 + }, D.Vector.prototype.toArray = function() { + for (var e = new Array(this.elements.length / 2), t = 1, n = 0; t < this.elements.length; t += 2, n++) e[n] = this.elements[t]; + return e + }, D.Vector.prototype.toJSON = function() { + return this.elements + }, D.stemmer = (l = { + ational: "ate", + tional: "tion", + enci: "ence", + anci: "ance", + izer: "ize", + bli: "ble", + alli: "al", + entli: "ent", + eli: "e", + ousli: "ous", + ization: "ize", + ation: "ate", + ator: "ate", + alism: "al", + iveness: "ive", + fulness: "ful", + ousness: "ous", + aliti: "al", + iviti: "ive", + biliti: "ble", + logi: "log" + }, u = { + icate: "ic", + ative: "", + alize: "al", + iciti: "ic", + ical: "ic", + ful: "", + ness: "" + }, e = "[aeiouy]", n = "[^aeiou][^aeiouy]*", f = new RegExp("^([^aeiou][^aeiouy]*)?[aeiouy][aeiou]*[^aeiou][^aeiouy]*"), d = new RegExp("^([^aeiou][^aeiouy]*)?[aeiouy][aeiou]*[^aeiou][^aeiouy]*[aeiouy][aeiou]*[^aeiou][^aeiouy]*"), h = new RegExp("^([^aeiou][^aeiouy]*)?[aeiouy][aeiou]*[^aeiou][^aeiouy]*([aeiouy][aeiou]*)?$"), p = new RegExp("^([^aeiou][^aeiouy]*)?[aeiouy]"), m = /^(.+?)(ss|i)es$/, y = /^(.+?)([^s])s$/, v = /^(.+?)eed$/, g = /^(.+?)(ed|ing)$/, w = /.$/, _ = /(at|bl|iz)$/, E = new RegExp("([^aeiouylsz])\\1$"), x = new RegExp("^" + n + e + "[^aeiouwxy]$"), b = /^(.+?[^aeiou])y$/, k = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/, S = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/, T = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/, L = /^(.+?)(s|t)(ion)$/, R = /^(.+?)e$/, O = /ll$/, C = new RegExp("^" + n + e + "[^aeiouwxy]$"), r = function(e) { + var t, n, r, i, o, a, s; + if (e.length < 3) return e; + if ("y" == (r = e.substr(0, 1)) && (e = r.toUpperCase() + e.substr(1)), o = y, (i = m).test(e) ? e = e.replace(i, "$1$2") : o.test(e) && (e = e.replace(o, "$1$2")), o = g, (i = v).test(e)) { + var c = i.exec(e); + (i = f).test(c[1]) && (i = w, e = e.replace(i, "")) + } else if (o.test(e)) { + t = (c = o.exec(e))[1], (o = p).test(t) && (a = E, s = x, (o = _).test(e = t) ? e += "e" : a.test(e) ? (i = w, e = e.replace(i, "")) : s.test(e) && (e += "e")) + }(i = b).test(e) && (e = (t = (c = i.exec(e))[1]) + "i"); + (i = k).test(e) && (t = (c = i.exec(e))[1], n = c[2], (i = f).test(t) && (e = t + l[n])); + (i = S).test(e) && (t = (c = i.exec(e))[1], n = c[2], (i = f).test(t) && (e = t + u[n])); + if (o = L, (i = T).test(e)) t = (c = i.exec(e))[1], (i = d).test(t) && (e = t); + else if (o.test(e)) { + t = (c = o.exec(e))[1] + c[2], (o = d).test(t) && (e = t) + }(i = R).test(e) && (t = (c = i.exec(e))[1], o = h, a = C, ((i = d).test(t) || o.test(t) && !a.test(t)) && (e = t)); + return o = d, (i = O).test(e) && o.test(e) && (i = w, e = e.replace(i, "")), "y" == r && (e = r.toLowerCase() + e.substr(1)), e + }, function(e) { + return e.update(r) + }), D.Pipeline.registerFunction(D.stemmer, "stemmer"), D.generateStopWordFilter = function(e) { + var t = e.reduce(function(e, t) { + return e[t] = t, e + }, {}); + return function(e) { + if (e && t[e.toString()] !== e.toString()) return e + } + }, D.stopWordFilter = D.generateStopWordFilter(["a", "able", "about", "across", "after", "all", "almost", "also", "am", "among", "an", "and", "any", "are", "as", "at", "be", "because", "been", "but", "by", "can", "cannot", "could", "dear", "did", "do", "does", "either", "else", "ever", "every", "for", "from", "get", "got", "had", "has", "have", "he", "her", "hers", "him", "his", "how", "however", "i", "if", "in", "into", "is", "it", "its", "just", "least", "let", "like", "likely", "may", "me", "might", "most", "must", "my", "neither", "no", "nor", "not", "of", "off", "often", "on", "only", "or", "other", "our", "own", "rather", "said", "say", "says", "she", "should", "since", "so", "some", "than", "that", "the", "their", "them", "then", "there", "these", "they", "this", "tis", "to", "too", "twas", "us", "wants", "was", "we", "were", "what", "when", "where", "which", "while", "who", "whom", "why", "will", "with", "would", "yet", "you", "your"]), D.Pipeline.registerFunction(D.stopWordFilter, "stopWordFilter"), D.trimmer = function(e) { + return e.update(function(e) { + return e.replace(/^\W+/, "").replace(/\W+$/, "") + }) + }, D.Pipeline.registerFunction(D.trimmer, "trimmer"), D.TokenSet = function() { + this.final = !1, this.edges = {}, this.id = D.TokenSet._nextId, D.TokenSet._nextId += 1 + }, D.TokenSet._nextId = 1, D.TokenSet.fromArray = function(e) { + for (var t = new D.TokenSet.Builder, n = 0, r = e.length; n < r; n++) t.insert(e[n]); + return t.finish(), t.root + }, D.TokenSet.fromClause = function(e) { + return "editDistance" in e ? D.TokenSet.fromFuzzyString(e.term, e.editDistance) : D.TokenSet.fromString(e.term) + }, D.TokenSet.fromFuzzyString = function(e, t) { + for (var n = new D.TokenSet, r = [{ + node: n, + editsRemaining: t, + str: e + }]; r.length;) { + var i = r.pop(); + if (0 < i.str.length) { + var o, a = i.str.charAt(0); + a in i.node.edges ? o = i.node.edges[a] : (o = new D.TokenSet, i.node.edges[a] = o), 1 == i.str.length && (o.final = !0), r.push({ + node: o, + editsRemaining: i.editsRemaining, + str: i.str.slice(1) + }) + } + if (0 != i.editsRemaining) { + if ("*" in i.node.edges) var s = i.node.edges["*"]; + else { + s = new D.TokenSet; + i.node.edges["*"] = s + } + if (0 == i.str.length && (s.final = !0), r.push({ + node: s, + editsRemaining: i.editsRemaining - 1, + str: i.str + }), 1 < i.str.length && r.push({ + node: i.node, + editsRemaining: i.editsRemaining - 1, + str: i.str.slice(1) + }), 1 == i.str.length && (i.node.final = !0), 1 <= i.str.length) { + if ("*" in i.node.edges) var c = i.node.edges["*"]; + else { + c = new D.TokenSet; + i.node.edges["*"] = c + } + 1 == i.str.length && (c.final = !0), r.push({ + node: c, + editsRemaining: i.editsRemaining - 1, + str: i.str.slice(1) + }) + } + if (1 < i.str.length) { + var l, u = i.str.charAt(0), + f = i.str.charAt(1); + f in i.node.edges ? l = i.node.edges[f] : (l = new D.TokenSet, i.node.edges[f] = l), 1 == i.str.length && (l.final = !0), r.push({ + node: l, + editsRemaining: i.editsRemaining - 1, + str: u + i.str.slice(2) + }) + } + } + } + return n + }, D.TokenSet.fromString = function(e) { + for (var t = new D.TokenSet, n = t, r = 0, i = e.length; r < i; r++) { + var o = e[r], + a = r == i - 1; + if ("*" == o)(t.edges[o] = t).final = a; + else { + var s = new D.TokenSet; + s.final = a, t.edges[o] = s, t = s + } + } + return n + }, D.TokenSet.prototype.toArray = function() { + for (var e = [], t = [{ + prefix: "", + node: this + }]; t.length;) { + var n = t.pop(), + r = Object.keys(n.node.edges), + i = r.length; + n.node.final && (n.prefix.charAt(0), e.push(n.prefix)); + for (var o = 0; o < i; o++) { + var a = r[o]; + t.push({ + prefix: n.prefix.concat(a), + node: n.node.edges[a] + }) + } + } + return e + }, D.TokenSet.prototype.toString = function() { + if (this._str) return this._str; + for (var e = this.final ? "1" : "0", t = Object.keys(this.edges).sort(), n = t.length, r = 0; r < n; r++) { + var i = t[r]; + e = e + i + this.edges[i].id + } + return e + }, D.TokenSet.prototype.intersect = function(e) { + for (var t = new D.TokenSet, n = void 0, r = [{ + qNode: e, + output: t, + node: this + }]; r.length;) { + n = r.pop(); + for (var i = Object.keys(n.qNode.edges), o = i.length, a = Object.keys(n.node.edges), s = a.length, c = 0; c < o; c++) + for (var l = i[c], u = 0; u < s; u++) { + var f = a[u]; + if (f == l || "*" == l) { + var d = n.node.edges[f], + h = n.qNode.edges[l], + p = d.final && h.final, + m = void 0; + f in n.output.edges ? (m = n.output.edges[f]).final = m.final || p : ((m = new D.TokenSet).final = p, n.output.edges[f] = m), r.push({ + qNode: h, + output: m, + node: d + }) + } + } + } + return t + }, D.TokenSet.Builder = function() { + this.previousWord = "", this.root = new D.TokenSet, this.uncheckedNodes = [], this.minimizedNodes = {} + }, D.TokenSet.Builder.prototype.insert = function(e) { + var t, n = 0; + if (e < this.previousWord) throw new Error("Out of order word insertion"); + for (var r = 0; r < e.length && r < this.previousWord.length && e[r] == this.previousWord[r]; r++) n++; + this.minimize(n), t = 0 == this.uncheckedNodes.length ? this.root : this.uncheckedNodes[this.uncheckedNodes.length - 1].child; + for (r = n; r < e.length; r++) { + var i = new D.TokenSet, + o = e[r]; + t.edges[o] = i, this.uncheckedNodes.push({ + parent: t, + char: o, + child: i + }), t = i + } + t.final = !0, this.previousWord = e + }, D.TokenSet.Builder.prototype.finish = function() { + this.minimize(0) + }, D.TokenSet.Builder.prototype.minimize = function(e) { + for (var t = this.uncheckedNodes.length - 1; e <= t; t--) { + var n = this.uncheckedNodes[t], + r = n.child.toString(); + r in this.minimizedNodes ? n.parent.edges[n.char] = this.minimizedNodes[r] : (n.child._str = r, this.minimizedNodes[r] = n.child), this.uncheckedNodes.pop() + } + }, D.Index = function(e) { + this.invertedIndex = e.invertedIndex, this.fieldVectors = e.fieldVectors, this.tokenSet = e.tokenSet, this.fields = e.fields, this.pipeline = e.pipeline + }, D.Index.prototype.search = function(t) { + return this.query(function(e) { + new D.QueryParser(t, e).parse() + }) + }, D.Index.prototype.query = function(e) { + for (var t = new D.Query(this.fields), n = Object.create(null), r = Object.create(null), i = Object.create(null), o = Object.create(null), a = Object.create(null), s = 0; s < this.fields.length; s++) r[this.fields[s]] = new D.Vector; + e.call(t, t); + for (s = 0; s < t.clauses.length; s++) { + var c = t.clauses[s], + l = null, + u = D.Set.complete; + l = c.usePipeline ? this.pipeline.runString(c.term, { + fields: c.fields + }) : [c.term]; + for (var f = 0; f < l.length; f++) { + var d = l[f]; + c.term = d; + var h = D.TokenSet.fromClause(c), + p = this.tokenSet.intersect(h).toArray(); + if (0 === p.length && c.presence === D.Query.presence.REQUIRED) { + for (var m = 0; m < c.fields.length; m++) { + o[Q = c.fields[m]] = D.Set.empty + } + break + } + for (var y = 0; y < p.length; y++) { + var v = p[y], + g = this.invertedIndex[v], + w = g._index; + for (m = 0; m < c.fields.length; m++) { + var _ = g[Q = c.fields[m]], + E = Object.keys(_), + x = v + "/" + Q, + b = new D.Set(E); + if (c.presence == D.Query.presence.REQUIRED && (u = u.union(b), void 0 === o[Q] && (o[Q] = D.Set.complete)), c.presence != D.Query.presence.PROHIBITED) { + if (r[Q].upsert(w, c.boost, function(e, t) { + return e + t + }), !i[x]) { + for (var k = 0; k < E.length; k++) { + var S, T = E[k], + L = new D.FieldRef(T, Q), + R = _[T]; + void 0 === (S = n[L]) ? n[L] = new D.MatchData(v, Q, R) : S.add(v, Q, R) + } + i[x] = !0 + } + } else void 0 === a[Q] && (a[Q] = D.Set.empty), a[Q] = a[Q].union(b) + } + } + } + if (c.presence === D.Query.presence.REQUIRED) + for (m = 0; m < c.fields.length; m++) { + o[Q = c.fields[m]] = o[Q].intersect(u) + } + } + var O = D.Set.complete, + C = D.Set.empty; + for (s = 0; s < this.fields.length; s++) { + var Q; + o[Q = this.fields[s]] && (O = O.intersect(o[Q])), a[Q] && (C = C.union(a[Q])) + } + var P = Object.keys(n), + A = [], + I = Object.create(null); + if (t.isNegated()) { + P = Object.keys(this.fieldVectors); + for (s = 0; s < P.length; s++) { + L = P[s]; + var M = D.FieldRef.fromString(L); + n[L] = new D.MatchData + } + } + for (s = 0; s < P.length; s++) { + var N = (M = D.FieldRef.fromString(P[s])).docRef; + if (O.contains(N) && !C.contains(N)) { + var j, F = this.fieldVectors[M], + H = r[M.fieldName].similarity(F); + if (void 0 !== (j = I[N])) j.score += H, j.matchData.combine(n[M]); + else { + var q = { + ref: N, + score: H, + matchData: n[M] + }; + I[N] = q, A.push(q) + } + } + } + return A.sort(function(e, t) { + return t.score - e.score + }) + }, D.Index.prototype.toJSON = function() { + var e = Object.keys(this.invertedIndex).sort().map(function(e) { + return [e, this.invertedIndex[e]] + }, this), + t = Object.keys(this.fieldVectors).map(function(e) { + return [e, this.fieldVectors[e].toJSON()] + }, this); + return { + version: D.version, + fields: this.fields, + fieldVectors: t, + invertedIndex: e, + pipeline: this.pipeline.toJSON() + } + }, D.Index.load = function(e) { + var t = {}, + n = {}, + r = e.fieldVectors, + i = Object.create(null), + o = e.invertedIndex, + a = new D.TokenSet.Builder, + s = D.Pipeline.load(e.pipeline); + e.version != D.version && D.utils.warn("Version mismatch when loading serialised index. Current version of lunr '" + D.version + "' does not match serialized index '" + e.version + "'"); + for (var c = 0; c < r.length; c++) { + var l = (f = r[c])[0], + u = f[1]; + n[l] = new D.Vector(u) + } + for (c = 0; c < o.length; c++) { + var f, d = (f = o[c])[0], + h = f[1]; + a.insert(d), i[d] = h + } + return a.finish(), t.fields = e.fields, t.fieldVectors = n, t.invertedIndex = i, t.tokenSet = a.root, t.pipeline = s, new D.Index(t) + }, D.Builder = function() { + this._ref = "id", this._fields = Object.create(null), this._documents = Object.create(null), this.invertedIndex = Object.create(null), this.fieldTermFrequencies = {}, this.fieldLengths = {}, this.tokenizer = D.tokenizer, this.pipeline = new D.Pipeline, this.searchPipeline = new D.Pipeline, this.documentCount = 0, this._b = .75, this._k1 = 1.2, this.termIndex = 0, this.metadataWhitelist = [] + }, D.Builder.prototype.ref = function(e) { + this._ref = e + }, D.Builder.prototype.field = function(e, t) { + if (/\//.test(e)) throw new RangeError("Field '" + e + "' contains illegal character '/'"); + this._fields[e] = t || {} + }, D.Builder.prototype.b = function(e) { + this._b = e < 0 ? 0 : 1 < e ? 1 : e + }, D.Builder.prototype.k1 = function(e) { + this._k1 = e + }, D.Builder.prototype.add = function(e, t) { + var n = e[this._ref], + r = Object.keys(this._fields); + this._documents[n] = t || {}, this.documentCount += 1; + for (var i = 0; i < r.length; i++) { + var o = r[i], + a = this._fields[o].extractor, + s = a ? a(e) : e[o], + c = this.tokenizer(s, { + fields: [o] + }), + l = this.pipeline.run(c), + u = new D.FieldRef(n, o), + f = Object.create(null); + this.fieldTermFrequencies[u] = f, this.fieldLengths[u] = 0, this.fieldLengths[u] += l.length; + for (var d = 0; d < l.length; d++) { + var h = l[d]; + if (null == f[h] && (f[h] = 0), f[h] += 1, null == this.invertedIndex[h]) { + var p = Object.create(null); + p._index = this.termIndex, this.termIndex += 1; + for (var m = 0; m < r.length; m++) p[r[m]] = Object.create(null); + this.invertedIndex[h] = p + } + null == this.invertedIndex[h][o][n] && (this.invertedIndex[h][o][n] = Object.create(null)); + for (var y = 0; y < this.metadataWhitelist.length; y++) { + var v = this.metadataWhitelist[y], + g = h.metadata[v]; + null == this.invertedIndex[h][o][n][v] && (this.invertedIndex[h][o][n][v] = []), this.invertedIndex[h][o][n][v].push(g) + } + } + } + }, D.Builder.prototype.calculateAverageFieldLengths = function() { + for (var e = Object.keys(this.fieldLengths), t = e.length, n = {}, r = {}, i = 0; i < t; i++) { + var o = D.FieldRef.fromString(e[i]), + a = o.fieldName; + r[a] || (r[a] = 0), r[a] += 1, n[a] || (n[a] = 0), n[a] += this.fieldLengths[o] + } + var s = Object.keys(this._fields); + for (i = 0; i < s.length; i++) { + var c = s[i]; + n[c] = n[c] / r[c] + } + this.averageFieldLength = n + }, D.Builder.prototype.createFieldVectors = function() { + for (var e = {}, t = Object.keys(this.fieldTermFrequencies), n = t.length, r = Object.create(null), i = 0; i < n; i++) { + for (var o = D.FieldRef.fromString(t[i]), a = o.fieldName, s = this.fieldLengths[o], c = new D.Vector, l = this.fieldTermFrequencies[o], u = Object.keys(l), f = u.length, d = this._fields[a].boost || 1, h = this._documents[o.docRef].boost || 1, p = 0; p < f; p++) { + var m, y, v, g = u[p], + w = l[g], + _ = this.invertedIndex[g]._index; + void 0 === r[g] ? (m = D.idf(this.invertedIndex[g], this.documentCount), r[g] = m) : m = r[g], y = m * ((this._k1 + 1) * w) / (this._k1 * (1 - this._b + this._b * (s / this.averageFieldLength[a])) + w), y *= d, y *= h, v = Math.round(1e3 * y) / 1e3, c.insert(_, v) + } + e[o] = c + } + this.fieldVectors = e + }, D.Builder.prototype.createTokenSet = function() { + this.tokenSet = D.TokenSet.fromArray(Object.keys(this.invertedIndex).sort()) + }, D.Builder.prototype.build = function() { + return this.calculateAverageFieldLengths(), this.createFieldVectors(), this.createTokenSet(), new D.Index({ + invertedIndex: this.invertedIndex, + fieldVectors: this.fieldVectors, + tokenSet: this.tokenSet, + fields: Object.keys(this._fields), + pipeline: this.searchPipeline + }) + }, D.Builder.prototype.use = function(e) { + var t = Array.prototype.slice.call(arguments, 1); + t.unshift(this), e.apply(this, t) + }, D.MatchData = function(e, t, n) { + for (var r = Object.create(null), i = Object.keys(n || {}), o = 0; o < i.length; o++) { + var a = i[o]; + r[a] = n[a].slice() + } + this.metadata = Object.create(null), void 0 !== e && (this.metadata[e] = Object.create(null), this.metadata[e][t] = r) + }, D.MatchData.prototype.combine = function(e) { + for (var t = Object.keys(e.metadata), n = 0; n < t.length; n++) { + var r = t[n], + i = Object.keys(e.metadata[r]); + null == this.metadata[r] && (this.metadata[r] = Object.create(null)); + for (var o = 0; o < i.length; o++) { + var a = i[o], + s = Object.keys(e.metadata[r][a]); + null == this.metadata[r][a] && (this.metadata[r][a] = Object.create(null)); + for (var c = 0; c < s.length; c++) { + var l = s[c]; + null == this.metadata[r][a][l] ? this.metadata[r][a][l] = e.metadata[r][a][l] : this.metadata[r][a][l] = this.metadata[r][a][l].concat(e.metadata[r][a][l]) + } + } + } + }, D.MatchData.prototype.add = function(e, t, n) { + if (!(e in this.metadata)) return this.metadata[e] = Object.create(null), void(this.metadata[e][t] = n); + if (t in this.metadata[e]) + for (var r = Object.keys(n), i = 0; i < r.length; i++) { + var o = r[i]; + o in this.metadata[e][t] ? this.metadata[e][t][o] = this.metadata[e][t][o].concat(n[o]) : this.metadata[e][t][o] = n[o] + } else this.metadata[e][t] = n + }, D.Query = function(e) { + this.clauses = [], this.allFields = e + }, D.Query.wildcard = new String("*"), D.Query.wildcard.NONE = 0, D.Query.wildcard.LEADING = 1, D.Query.wildcard.TRAILING = 2, D.Query.presence = { + OPTIONAL: 1, + REQUIRED: 2, + PROHIBITED: 3 + }, D.Query.prototype.clause = function(e) { + return "fields" in e || (e.fields = this.allFields), "boost" in e || (e.boost = 1), "usePipeline" in e || (e.usePipeline = !0), "wildcard" in e || (e.wildcard = D.Query.wildcard.NONE), e.wildcard & D.Query.wildcard.LEADING && e.term.charAt(0) != D.Query.wildcard && (e.term = "*" + e.term), e.wildcard & D.Query.wildcard.TRAILING && e.term.slice(-1) != D.Query.wildcard && (e.term = e.term + "*"), "presence" in e || (e.presence = D.Query.presence.OPTIONAL), this.clauses.push(e), this + }, D.Query.prototype.isNegated = function() { + for (var e = 0; e < this.clauses.length; e++) + if (this.clauses[e].presence != D.Query.presence.PROHIBITED) return !1; + return !0 + }, D.Query.prototype.term = function(e, t) { + if (Array.isArray(e)) return e.forEach(function(e) { + this.term(e, D.utils.clone(t)) + }, this), this; + var n = t || {}; + return n.term = e.toString(), this.clause(n), this + }, D.QueryParseError = function(e, t, n) { + this.name = "QueryParseError", this.message = e, this.start = t, this.end = n + }, D.QueryParseError.prototype = new Error, D.QueryLexer = function(e) { + this.lexemes = [], this.str = e, this.length = e.length, this.pos = 0, this.start = 0, this.escapeCharPositions = [] + }, D.QueryLexer.prototype.run = function() { + for (var e = D.QueryLexer.lexText; e;) e = e(this) + }, D.QueryLexer.prototype.sliceString = function() { + for (var e = [], t = this.start, n = this.pos, r = 0; r < this.escapeCharPositions.length; r++) n = this.escapeCharPositions[r], e.push(this.str.slice(t, n)), t = n + 1; + return e.push(this.str.slice(t, this.pos)), this.escapeCharPositions.length = 0, e.join("") + }, D.QueryLexer.prototype.emit = function(e) { + this.lexemes.push({ + type: e, + str: this.sliceString(), + start: this.start, + end: this.pos + }), this.start = this.pos + }, D.QueryLexer.prototype.escapeCharacter = function() { + this.escapeCharPositions.push(this.pos - 1), this.pos += 1 + }, D.QueryLexer.prototype.next = function() { + if (this.pos >= this.length) return D.QueryLexer.EOS; + var e = this.str.charAt(this.pos); + return this.pos += 1, e + }, D.QueryLexer.prototype.width = function() { + return this.pos - this.start + }, D.QueryLexer.prototype.ignore = function() { + this.start == this.pos && (this.pos += 1), this.start = this.pos + }, D.QueryLexer.prototype.backup = function() { + this.pos -= 1 + }, D.QueryLexer.prototype.acceptDigitRun = function() { + for (var e, t; 47 < (t = (e = this.next()).charCodeAt(0)) && t < 58;); + e != D.QueryLexer.EOS && this.backup() + }, D.QueryLexer.prototype.more = function() { + return this.pos < this.length + }, D.QueryLexer.EOS = "EOS", D.QueryLexer.FIELD = "FIELD", D.QueryLexer.TERM = "TERM", D.QueryLexer.EDIT_DISTANCE = "EDIT_DISTANCE", D.QueryLexer.BOOST = "BOOST", D.QueryLexer.PRESENCE = "PRESENCE", D.QueryLexer.lexField = function(e) { + return e.backup(), e.emit(D.QueryLexer.FIELD), e.ignore(), D.QueryLexer.lexText + }, D.QueryLexer.lexTerm = function(e) { + if (1 < e.width() && (e.backup(), e.emit(D.QueryLexer.TERM)), e.ignore(), e.more()) return D.QueryLexer.lexText + }, D.QueryLexer.lexEditDistance = function(e) { + return e.ignore(), e.acceptDigitRun(), e.emit(D.QueryLexer.EDIT_DISTANCE), D.QueryLexer.lexText + }, D.QueryLexer.lexBoost = function(e) { + return e.ignore(), e.acceptDigitRun(), e.emit(D.QueryLexer.BOOST), D.QueryLexer.lexText + }, D.QueryLexer.lexEOS = function(e) { + 0 < e.width() && e.emit(D.QueryLexer.TERM) + }, D.QueryLexer.termSeparator = D.tokenizer.separator, D.QueryLexer.lexText = function(e) { + for (;;) { + var t = e.next(); + if (t == D.QueryLexer.EOS) return D.QueryLexer.lexEOS; + if (92 != t.charCodeAt(0)) { + if (":" == t) return D.QueryLexer.lexField; + if ("~" == t) return e.backup(), 0 < e.width() && e.emit(D.QueryLexer.TERM), D.QueryLexer.lexEditDistance; + if ("^" == t) return e.backup(), 0 < e.width() && e.emit(D.QueryLexer.TERM), D.QueryLexer.lexBoost; + if ("+" == t && 1 === e.width()) return e.emit(D.QueryLexer.PRESENCE), D.QueryLexer.lexText; + if ("-" == t && 1 === e.width()) return e.emit(D.QueryLexer.PRESENCE), D.QueryLexer.lexText; + if (t.match(D.QueryLexer.termSeparator)) return D.QueryLexer.lexTerm + } else e.escapeCharacter() + } + }, D.QueryParser = function(e, t) { + this.lexer = new D.QueryLexer(e), this.query = t, this.currentClause = {}, this.lexemeIdx = 0 + }, D.QueryParser.prototype.parse = function() { + this.lexer.run(), this.lexemes = this.lexer.lexemes; + for (var e = D.QueryParser.parseClause; e;) e = e(this); + return this.query + }, D.QueryParser.prototype.peekLexeme = function() { + return this.lexemes[this.lexemeIdx] + }, D.QueryParser.prototype.consumeLexeme = function() { + var e = this.peekLexeme(); + return this.lexemeIdx += 1, e + }, D.QueryParser.prototype.nextClause = function() { + var e = this.currentClause; + this.query.clause(e), this.currentClause = {} + }, D.QueryParser.parseClause = function(e) { + var t = e.peekLexeme(); + if (null != t) switch (t.type) { + case D.QueryLexer.PRESENCE: + return D.QueryParser.parsePresence; + case D.QueryLexer.FIELD: + return D.QueryParser.parseField; + case D.QueryLexer.TERM: + return D.QueryParser.parseTerm; + default: + var n = "expected either a field or a term, found " + t.type; + throw 1 <= t.str.length && (n += " with value '" + t.str + "'"), new D.QueryParseError(n, t.start, t.end) + } + }, D.QueryParser.parsePresence = function(e) { + var t = e.consumeLexeme(); + if (null != t) { + switch (t.str) { + case "-": + e.currentClause.presence = D.Query.presence.PROHIBITED; + break; + case "+": + e.currentClause.presence = D.Query.presence.REQUIRED; + break; + default: + var n = "unrecognised presence operator'" + t.str + "'"; + throw new D.QueryParseError(n, t.start, t.end) + } + var r = e.peekLexeme(); + if (null == r) { + n = "expecting term or field, found nothing"; + throw new D.QueryParseError(n, t.start, t.end) + } + switch (r.type) { + case D.QueryLexer.FIELD: + return D.QueryParser.parseField; + case D.QueryLexer.TERM: + return D.QueryParser.parseTerm; + default: + n = "expecting term or field, found '" + r.type + "'"; + throw new D.QueryParseError(n, r.start, r.end) + } + } + }, D.QueryParser.parseField = function(e) { + var t = e.consumeLexeme(); + if (null != t) { + if (-1 == e.query.allFields.indexOf(t.str)) { + var n = e.query.allFields.map(function(e) { + return "'" + e + "'" + }).join(", "), + r = "unrecognised field '" + t.str + "', possible fields: " + n; + throw new D.QueryParseError(r, t.start, t.end) + } + e.currentClause.fields = [t.str]; + var i = e.peekLexeme(); + if (null == i) { + r = "expecting term, found nothing"; + throw new D.QueryParseError(r, t.start, t.end) + } + switch (i.type) { + case D.QueryLexer.TERM: + return D.QueryParser.parseTerm; + default: + r = "expecting term, found '" + i.type + "'"; + throw new D.QueryParseError(r, i.start, i.end) + } + } + }, D.QueryParser.parseTerm = function(e) { + var t = e.consumeLexeme(); + if (null != t) { + e.currentClause.term = t.str.toLowerCase(), -1 != t.str.indexOf("*") && (e.currentClause.usePipeline = !1); + var n = e.peekLexeme(); + if (null != n) switch (n.type) { + case D.QueryLexer.TERM: + return e.nextClause(), D.QueryParser.parseTerm; + case D.QueryLexer.FIELD: + return e.nextClause(), D.QueryParser.parseField; + case D.QueryLexer.EDIT_DISTANCE: + return D.QueryParser.parseEditDistance; + case D.QueryLexer.BOOST: + return D.QueryParser.parseBoost; + case D.QueryLexer.PRESENCE: + return e.nextClause(), D.QueryParser.parsePresence; + default: + var r = "Unexpected lexeme type '" + n.type + "'"; + throw new D.QueryParseError(r, n.start, n.end) + } else e.nextClause() + } + }, D.QueryParser.parseEditDistance = function(e) { + var t = e.consumeLexeme(); + if (null != t) { + var n = parseInt(t.str, 10); + if (isNaN(n)) { + var r = "edit distance must be numeric"; + throw new D.QueryParseError(r, t.start, t.end) + } + e.currentClause.editDistance = n; + var i = e.peekLexeme(); + if (null != i) switch (i.type) { + case D.QueryLexer.TERM: + return e.nextClause(), D.QueryParser.parseTerm; + case D.QueryLexer.FIELD: + return e.nextClause(), D.QueryParser.parseField; + case D.QueryLexer.EDIT_DISTANCE: + return D.QueryParser.parseEditDistance; + case D.QueryLexer.BOOST: + return D.QueryParser.parseBoost; + case D.QueryLexer.PRESENCE: + return e.nextClause(), D.QueryParser.parsePresence; + default: + r = "Unexpected lexeme type '" + i.type + "'"; + throw new D.QueryParseError(r, i.start, i.end) + } else e.nextClause() + } + }, D.QueryParser.parseBoost = function(e) { + var t = e.consumeLexeme(); + if (null != t) { + var n = parseInt(t.str, 10); + if (isNaN(n)) { + var r = "boost must be numeric"; + throw new D.QueryParseError(r, t.start, t.end) + } + e.currentClause.boost = n; + var i = e.peekLexeme(); + if (null != i) switch (i.type) { + case D.QueryLexer.TERM: + return e.nextClause(), D.QueryParser.parseTerm; + case D.QueryLexer.FIELD: + return e.nextClause(), D.QueryParser.parseField; + case D.QueryLexer.EDIT_DISTANCE: + return D.QueryParser.parseEditDistance; + case D.QueryLexer.BOOST: + return D.QueryParser.parseBoost; + case D.QueryLexer.PRESENCE: + return e.nextClause(), D.QueryParser.parsePresence; + default: + r = "Unexpected lexeme type '" + i.type + "'"; + throw new D.QueryParseError(r, i.start, i.end) + } else e.nextClause() + } + }, void 0 === (c = "function" == typeof(s = function() { + return D + }) ? s.call(o, a, o, i) : s) || (i.exports = c) + }() +}])); \ No newline at end of file diff --git a/_static/javascripts/lunr/lunr.da.js b/_static/javascripts/lunr/lunr.da.js new file mode 100644 index 0000000000..34910dfe5f --- /dev/null +++ b/_static/javascripts/lunr/lunr.da.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r,m,i;e.da=function(){this.pipeline.reset(),this.pipeline.add(e.da.trimmer,e.da.stopWordFilter,e.da.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.da.stemmer))},e.da.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.da.trimmer=e.trimmerSupport.generateTrimmer(e.da.wordCharacters),e.Pipeline.registerFunction(e.da.trimmer,"trimmer-da"),e.da.stemmer=(r=e.stemmerSupport.Among,m=e.stemmerSupport.SnowballProgram,i=new function(){var i,t,n,s=[new r("hed",-1,1),new r("ethed",0,1),new r("ered",-1,1),new r("e",-1,1),new r("erede",3,1),new r("ende",3,1),new r("erende",5,1),new r("ene",3,1),new r("erne",3,1),new r("ere",3,1),new r("en",-1,1),new r("heden",10,1),new r("eren",10,1),new r("er",-1,1),new r("heder",13,1),new r("erer",13,1),new r("s",-1,2),new r("heds",16,1),new r("es",16,1),new r("endes",18,1),new r("erendes",19,1),new r("enes",18,1),new r("ernes",18,1),new r("eres",18,1),new r("ens",16,1),new r("hedens",24,1),new r("erens",24,1),new r("ers",16,1),new r("ets",16,1),new r("erets",28,1),new r("et",-1,1),new r("eret",30,1)],o=[new r("gd",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1)],a=[new r("ig",-1,1),new r("lig",0,1),new r("elig",1,1),new r("els",-1,1),new r("løst",-1,2)],d=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],u=[239,254,42,3,0,0,0,0,0,0,0,0,0,0,0,0,16],c=new m;function l(){var e,r=c.limit-c.cursor;c.cursor>=t&&(e=c.limit_backward,c.limit_backward=t,c.ket=c.cursor,c.find_among_b(o,4)?(c.bra=c.cursor,c.limit_backward=e,c.cursor=c.limit-r,c.cursor>c.limit_backward&&(c.cursor--,c.bra=c.cursor,c.slice_del())):c.limit_backward=e)}this.setCurrent=function(e){c.setCurrent(e)},this.getCurrent=function(){return c.getCurrent()},this.stem=function(){var e,r=c.cursor;return function(){var e,r=c.cursor+3;if(t=c.limit,0<=r&&r<=c.limit){for(i=r;;){if(e=c.cursor,c.in_grouping(d,97,248)){c.cursor=e;break}if((c.cursor=e)>=c.limit)return;c.cursor++}for(;!c.out_grouping(d,97,248);){if(c.cursor>=c.limit)return;c.cursor++}(t=c.cursor)=t&&(r=c.limit_backward,c.limit_backward=t,c.ket=c.cursor,e=c.find_among_b(s,32),c.limit_backward=r,e))switch(c.bra=c.cursor,e){case 1:c.slice_del();break;case 2:c.in_grouping_b(u,97,229)&&c.slice_del()}}(),c.cursor=c.limit,l(),c.cursor=c.limit,function(){var e,r,i,n=c.limit-c.cursor;if(c.ket=c.cursor,c.eq_s_b(2,"st")&&(c.bra=c.cursor,c.eq_s_b(2,"ig")&&c.slice_del()),c.cursor=c.limit-n,c.cursor>=t&&(r=c.limit_backward,c.limit_backward=t,c.ket=c.cursor,e=c.find_among_b(a,5),c.limit_backward=r,e))switch(c.bra=c.cursor,e){case 1:c.slice_del(),i=c.limit-c.cursor,l(),c.cursor=c.limit-i;break;case 2:c.slice_from("løs")}}(),c.cursor=c.limit,c.cursor>=t&&(e=c.limit_backward,c.limit_backward=t,c.ket=c.cursor,c.out_grouping_b(d,97,248)?(c.bra=c.cursor,n=c.slice_to(n),c.limit_backward=e,c.eq_v_b(n)&&c.slice_del()):c.limit_backward=e),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}),e.Pipeline.registerFunction(e.da.stemmer,"stemmer-da"),e.da.stopWordFilter=e.generateStopWordFilter("ad af alle alt anden at blev blive bliver da de dem den denne der deres det dette dig din disse dog du efter eller en end er et for fra ham han hans har havde have hende hendes her hos hun hvad hvis hvor i ikke ind jeg jer jo kunne man mange med meget men mig min mine mit mod ned noget nogle nu når og også om op os over på selv sig sin sine sit skal skulle som sådan thi til ud under var vi vil ville vor være været".split(" ")),e.Pipeline.registerFunction(e.da.stopWordFilter,"stopWordFilter-da")}}); \ No newline at end of file diff --git a/_static/javascripts/lunr/lunr.de.js b/_static/javascripts/lunr/lunr.de.js new file mode 100644 index 0000000000..1529892c82 --- /dev/null +++ b/_static/javascripts/lunr/lunr.de.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var _,p,r;e.de=function(){this.pipeline.reset(),this.pipeline.add(e.de.trimmer,e.de.stopWordFilter,e.de.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.de.stemmer))},e.de.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.de.trimmer=e.trimmerSupport.generateTrimmer(e.de.wordCharacters),e.Pipeline.registerFunction(e.de.trimmer,"trimmer-de"),e.de.stemmer=(_=e.stemmerSupport.Among,p=e.stemmerSupport.SnowballProgram,r=new function(){var r,n,i,s=[new _("",-1,6),new _("U",0,2),new _("Y",0,1),new _("ä",0,3),new _("ö",0,4),new _("ü",0,5)],o=[new _("e",-1,2),new _("em",-1,1),new _("en",-1,2),new _("ern",-1,1),new _("er",-1,1),new _("s",-1,3),new _("es",5,2)],c=[new _("en",-1,1),new _("er",-1,1),new _("st",-1,2),new _("est",2,1)],u=[new _("ig",-1,1),new _("lich",-1,1)],a=[new _("end",-1,1),new _("ig",-1,2),new _("ung",-1,1),new _("lich",-1,3),new _("isch",-1,2),new _("ik",-1,2),new _("heit",-1,3),new _("keit",-1,4)],t=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32,8],d=[117,30,5],l=[117,30,4],m=new p;function h(e,r,n){return!(!m.eq_s(1,e)||(m.ket=m.cursor,!m.in_grouping(t,97,252)))&&(m.slice_from(r),m.cursor=n,!0)}function w(){for(;!m.in_grouping(t,97,252);){if(m.cursor>=m.limit)return!0;m.cursor++}for(;!m.out_grouping(t,97,252);){if(m.cursor>=m.limit)return!0;m.cursor++}return!1}function f(){return i<=m.cursor}function b(){return n<=m.cursor}this.setCurrent=function(e){m.setCurrent(e)},this.getCurrent=function(){return m.getCurrent()},this.stem=function(){var e=m.cursor;return function(){for(var e,r,n,i,s=m.cursor;;)if(e=m.cursor,m.bra=e,m.eq_s(1,"ß"))m.ket=m.cursor,m.slice_from("ss");else{if(e>=m.limit)break;m.cursor=e+1}for(m.cursor=s;;)for(r=m.cursor;;){if(n=m.cursor,m.in_grouping(t,97,252)){if(i=m.cursor,m.bra=i,h("u","U",n))break;if(m.cursor=i,h("y","Y",n))break}if(n>=m.limit)return m.cursor=r;m.cursor=n+1}}(),m.cursor=e,function(){i=m.limit,n=i;var e=m.cursor+3;0<=e&&e<=m.limit&&(r=e,w()||((i=m.cursor)=m.limit)return;m.cursor++}}}(),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return r.setCurrent(e),r.stem(),r.getCurrent()}):(r.setCurrent(e),r.stem(),r.getCurrent())}),e.Pipeline.registerFunction(e.de.stemmer,"stemmer-de"),e.de.stopWordFilter=e.generateStopWordFilter("aber alle allem allen aller alles als also am an ander andere anderem anderen anderer anderes anderm andern anderr anders auch auf aus bei bin bis bist da damit dann das dasselbe dazu daß dein deine deinem deinen deiner deines dem demselben den denn denselben der derer derselbe derselben des desselben dessen dich die dies diese dieselbe dieselben diesem diesen dieser dieses dir doch dort du durch ein eine einem einen einer eines einig einige einigem einigen einiger einiges einmal er es etwas euch euer eure eurem euren eurer eures für gegen gewesen hab habe haben hat hatte hatten hier hin hinter ich ihm ihn ihnen ihr ihre ihrem ihren ihrer ihres im in indem ins ist jede jedem jeden jeder jedes jene jenem jenen jener jenes jetzt kann kein keine keinem keinen keiner keines können könnte machen man manche manchem manchen mancher manches mein meine meinem meinen meiner meines mich mir mit muss musste nach nicht nichts noch nun nur ob oder ohne sehr sein seine seinem seinen seiner seines selbst sich sie sind so solche solchem solchen solcher solches soll sollte sondern sonst um und uns unse unsem unsen unser unses unter viel vom von vor war waren warst was weg weil weiter welche welchem welchen welcher welches wenn werde werden wie wieder will wir wird wirst wo wollen wollte während würde würden zu zum zur zwar zwischen über".split(" ")),e.Pipeline.registerFunction(e.de.stopWordFilter,"stopWordFilter-de")}}); \ No newline at end of file diff --git a/_static/javascripts/lunr/lunr.du.js b/_static/javascripts/lunr/lunr.du.js new file mode 100644 index 0000000000..52632004a2 --- /dev/null +++ b/_static/javascripts/lunr/lunr.du.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var v,q,r;console.warn('[Lunr Languages] Please use the "nl" instead of the "du". The "nl" code is the standard code for Dutch language, and "du" will be removed in the next major versions.'),e.du=function(){this.pipeline.reset(),this.pipeline.add(e.du.trimmer,e.du.stopWordFilter,e.du.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.du.stemmer))},e.du.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.du.trimmer=e.trimmerSupport.generateTrimmer(e.du.wordCharacters),e.Pipeline.registerFunction(e.du.trimmer,"trimmer-du"),e.du.stemmer=(v=e.stemmerSupport.Among,q=e.stemmerSupport.SnowballProgram,r=new function(){var r,i,u,o=[new v("",-1,6),new v("á",0,1),new v("ä",0,1),new v("é",0,2),new v("ë",0,2),new v("í",0,3),new v("ï",0,3),new v("ó",0,4),new v("ö",0,4),new v("ú",0,5),new v("ü",0,5)],n=[new v("",-1,3),new v("I",0,2),new v("Y",0,1)],t=[new v("dd",-1,-1),new v("kk",-1,-1),new v("tt",-1,-1)],c=[new v("ene",-1,2),new v("se",-1,3),new v("en",-1,2),new v("heden",2,1),new v("s",-1,3)],a=[new v("end",-1,1),new v("ig",-1,2),new v("ing",-1,1),new v("lijk",-1,3),new v("baar",-1,4),new v("bar",-1,5)],l=[new v("aa",-1,-1),new v("ee",-1,-1),new v("oo",-1,-1),new v("uu",-1,-1)],m=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],d=[1,0,0,17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],f=[17,67,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],_=new q;function s(e){return(_.cursor=e)>=_.limit||(_.cursor++,!1)}function w(){for(;!_.in_grouping(m,97,232);){if(_.cursor>=_.limit)return!0;_.cursor++}for(;!_.out_grouping(m,97,232);){if(_.cursor>=_.limit)return!0;_.cursor++}return!1}function b(){return i<=_.cursor}function p(){return r<=_.cursor}function g(){var e=_.limit-_.cursor;_.find_among_b(t,3)&&(_.cursor=_.limit-e,_.ket=_.cursor,_.cursor>_.limit_backward&&(_.cursor--,_.bra=_.cursor,_.slice_del()))}function h(){var e;u=!1,_.ket=_.cursor,_.eq_s_b(1,"e")&&(_.bra=_.cursor,b()&&(e=_.limit-_.cursor,_.out_grouping_b(m,97,232)&&(_.cursor=_.limit-e,_.slice_del(),u=!0,g())))}function k(){var e;b()&&(e=_.limit-_.cursor,_.out_grouping_b(m,97,232)&&(_.cursor=_.limit-e,_.eq_s_b(3,"gem")||(_.cursor=_.limit-e,_.slice_del(),g())))}this.setCurrent=function(e){_.setCurrent(e)},this.getCurrent=function(){return _.getCurrent()},this.stem=function(){var e=_.cursor;return function(){for(var e,r,i,n=_.cursor;;){if(_.bra=_.cursor,e=_.find_among(o,11))switch(_.ket=_.cursor,e){case 1:_.slice_from("a");continue;case 2:_.slice_from("e");continue;case 3:_.slice_from("i");continue;case 4:_.slice_from("o");continue;case 5:_.slice_from("u");continue;case 6:if(_.cursor>=_.limit)break;_.cursor++;continue}break}for(_.cursor=n,_.bra=n,_.eq_s(1,"y")?(_.ket=_.cursor,_.slice_from("Y")):_.cursor=n;;)if(r=_.cursor,_.in_grouping(m,97,232)){if(i=_.cursor,_.bra=i,_.eq_s(1,"i"))_.ket=_.cursor,_.in_grouping(m,97,232)&&(_.slice_from("I"),_.cursor=r);else if(_.cursor=i,_.eq_s(1,"y"))_.ket=_.cursor,_.slice_from("Y"),_.cursor=r;else if(s(r))break}else if(s(r))break}(),_.cursor=e,i=_.limit,r=i,w()||((i=_.cursor)<3&&(i=3),w()||(r=_.cursor)),_.limit_backward=e,_.cursor=_.limit,function(){var e,r,i,n,o,t,s=_.limit-_.cursor;if(_.ket=_.cursor,e=_.find_among_b(c,5))switch(_.bra=_.cursor,e){case 1:b()&&_.slice_from("heid");break;case 2:k();break;case 3:b()&&_.out_grouping_b(f,97,232)&&_.slice_del()}if(_.cursor=_.limit-s,h(),_.cursor=_.limit-s,_.ket=_.cursor,_.eq_s_b(4,"heid")&&(_.bra=_.cursor,p()&&(r=_.limit-_.cursor,_.eq_s_b(1,"c")||(_.cursor=_.limit-r,_.slice_del(),_.ket=_.cursor,_.eq_s_b(2,"en")&&(_.bra=_.cursor,k())))),_.cursor=_.limit-s,_.ket=_.cursor,e=_.find_among_b(a,6))switch(_.bra=_.cursor,e){case 1:if(p()){if(_.slice_del(),i=_.limit-_.cursor,_.ket=_.cursor,_.eq_s_b(2,"ig")&&(_.bra=_.cursor,p()&&(n=_.limit-_.cursor,!_.eq_s_b(1,"e")))){_.cursor=_.limit-n,_.slice_del();break}_.cursor=_.limit-i,g()}break;case 2:p()&&(o=_.limit-_.cursor,_.eq_s_b(1,"e")||(_.cursor=_.limit-o,_.slice_del()));break;case 3:p()&&(_.slice_del(),h());break;case 4:p()&&_.slice_del();break;case 5:p()&&u&&_.slice_del()}_.cursor=_.limit-s,_.out_grouping_b(d,73,232)&&(t=_.limit-_.cursor,_.find_among_b(l,4)&&_.out_grouping_b(m,97,232)&&(_.cursor=_.limit-t,_.ket=_.cursor,_.cursor>_.limit_backward&&(_.cursor--,_.bra=_.cursor,_.slice_del())))}(),_.cursor=_.limit_backward,function(){for(var e;;)if(_.bra=_.cursor,e=_.find_among(n,3))switch(_.ket=_.cursor,e){case 1:_.slice_from("y");break;case 2:_.slice_from("i");break;case 3:if(_.cursor>=_.limit)return;_.cursor++}}(),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return r.setCurrent(e),r.stem(),r.getCurrent()}):(r.setCurrent(e),r.stem(),r.getCurrent())}),e.Pipeline.registerFunction(e.du.stemmer,"stemmer-du"),e.du.stopWordFilter=e.generateStopWordFilter(" aan al alles als altijd andere ben bij daar dan dat de der deze die dit doch doen door dus een eens en er ge geen geweest haar had heb hebben heeft hem het hier hij hoe hun iemand iets ik in is ja je kan kon kunnen maar me meer men met mij mijn moet na naar niet niets nog nu of om omdat onder ons ook op over reeds te tegen toch toen tot u uit uw van veel voor want waren was wat werd wezen wie wil worden wordt zal ze zelf zich zij zijn zo zonder zou".split(" ")),e.Pipeline.registerFunction(e.du.stopWordFilter,"stopWordFilter-du")}}); \ No newline at end of file diff --git a/_static/javascripts/lunr/lunr.es.js b/_static/javascripts/lunr/lunr.es.js new file mode 100644 index 0000000000..9de6c09cb4 --- /dev/null +++ b/_static/javascripts/lunr/lunr.es.js @@ -0,0 +1 @@ +!function(e,s){"function"==typeof define&&define.amd?define(s):"object"==typeof exports?module.exports=s():s()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var C,P,s;e.es=function(){this.pipeline.reset(),this.pipeline.add(e.es.trimmer,e.es.stopWordFilter,e.es.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.es.stemmer))},e.es.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.es.trimmer=e.trimmerSupport.generateTrimmer(e.es.wordCharacters),e.Pipeline.registerFunction(e.es.trimmer,"trimmer-es"),e.es.stemmer=(C=e.stemmerSupport.Among,P=e.stemmerSupport.SnowballProgram,s=new function(){var r,n,i,a=[new C("",-1,6),new C("á",0,1),new C("é",0,2),new C("í",0,3),new C("ó",0,4),new C("ú",0,5)],t=[new C("la",-1,-1),new C("sela",0,-1),new C("le",-1,-1),new C("me",-1,-1),new C("se",-1,-1),new C("lo",-1,-1),new C("selo",5,-1),new C("las",-1,-1),new C("selas",7,-1),new C("les",-1,-1),new C("los",-1,-1),new C("selos",10,-1),new C("nos",-1,-1)],o=[new C("ando",-1,6),new C("iendo",-1,6),new C("yendo",-1,7),new C("ándo",-1,2),new C("iéndo",-1,1),new C("ar",-1,6),new C("er",-1,6),new C("ir",-1,6),new C("ár",-1,3),new C("ér",-1,4),new C("ír",-1,5)],s=[new C("ic",-1,-1),new C("ad",-1,-1),new C("os",-1,-1),new C("iv",-1,1)],u=[new C("able",-1,1),new C("ible",-1,1),new C("ante",-1,1)],w=[new C("ic",-1,1),new C("abil",-1,1),new C("iv",-1,1)],c=[new C("ica",-1,1),new C("ancia",-1,2),new C("encia",-1,5),new C("adora",-1,2),new C("osa",-1,1),new C("ista",-1,1),new C("iva",-1,9),new C("anza",-1,1),new C("logía",-1,3),new C("idad",-1,8),new C("able",-1,1),new C("ible",-1,1),new C("ante",-1,2),new C("mente",-1,7),new C("amente",13,6),new C("ación",-1,2),new C("ución",-1,4),new C("ico",-1,1),new C("ismo",-1,1),new C("oso",-1,1),new C("amiento",-1,1),new C("imiento",-1,1),new C("ivo",-1,9),new C("ador",-1,2),new C("icas",-1,1),new C("ancias",-1,2),new C("encias",-1,5),new C("adoras",-1,2),new C("osas",-1,1),new C("istas",-1,1),new C("ivas",-1,9),new C("anzas",-1,1),new C("logías",-1,3),new C("idades",-1,8),new C("ables",-1,1),new C("ibles",-1,1),new C("aciones",-1,2),new C("uciones",-1,4),new C("adores",-1,2),new C("antes",-1,2),new C("icos",-1,1),new C("ismos",-1,1),new C("osos",-1,1),new C("amientos",-1,1),new C("imientos",-1,1),new C("ivos",-1,9)],m=[new C("ya",-1,1),new C("ye",-1,1),new C("yan",-1,1),new C("yen",-1,1),new C("yeron",-1,1),new C("yendo",-1,1),new C("yo",-1,1),new C("yas",-1,1),new C("yes",-1,1),new C("yais",-1,1),new C("yamos",-1,1),new C("yó",-1,1)],l=[new C("aba",-1,2),new C("ada",-1,2),new C("ida",-1,2),new C("ara",-1,2),new C("iera",-1,2),new C("ía",-1,2),new C("aría",5,2),new C("ería",5,2),new C("iría",5,2),new C("ad",-1,2),new C("ed",-1,2),new C("id",-1,2),new C("ase",-1,2),new C("iese",-1,2),new C("aste",-1,2),new C("iste",-1,2),new C("an",-1,2),new C("aban",16,2),new C("aran",16,2),new C("ieran",16,2),new C("ían",16,2),new C("arían",20,2),new C("erían",20,2),new C("irían",20,2),new C("en",-1,1),new C("asen",24,2),new C("iesen",24,2),new C("aron",-1,2),new C("ieron",-1,2),new C("arán",-1,2),new C("erán",-1,2),new C("irán",-1,2),new C("ado",-1,2),new C("ido",-1,2),new C("ando",-1,2),new C("iendo",-1,2),new C("ar",-1,2),new C("er",-1,2),new C("ir",-1,2),new C("as",-1,2),new C("abas",39,2),new C("adas",39,2),new C("idas",39,2),new C("aras",39,2),new C("ieras",39,2),new C("ías",39,2),new C("arías",45,2),new C("erías",45,2),new C("irías",45,2),new C("es",-1,1),new C("ases",49,2),new C("ieses",49,2),new C("abais",-1,2),new C("arais",-1,2),new C("ierais",-1,2),new C("íais",-1,2),new C("aríais",55,2),new C("eríais",55,2),new C("iríais",55,2),new C("aseis",-1,2),new C("ieseis",-1,2),new C("asteis",-1,2),new C("isteis",-1,2),new C("áis",-1,2),new C("éis",-1,1),new C("aréis",64,2),new C("eréis",64,2),new C("iréis",64,2),new C("ados",-1,2),new C("idos",-1,2),new C("amos",-1,2),new C("ábamos",70,2),new C("áramos",70,2),new C("iéramos",70,2),new C("íamos",70,2),new C("aríamos",74,2),new C("eríamos",74,2),new C("iríamos",74,2),new C("emos",-1,1),new C("aremos",78,2),new C("eremos",78,2),new C("iremos",78,2),new C("ásemos",78,2),new C("iésemos",78,2),new C("imos",-1,2),new C("arás",-1,2),new C("erás",-1,2),new C("irás",-1,2),new C("ís",-1,2),new C("ará",-1,2),new C("erá",-1,2),new C("irá",-1,2),new C("aré",-1,2),new C("eré",-1,2),new C("iré",-1,2),new C("ió",-1,2)],d=[new C("a",-1,1),new C("e",-1,2),new C("o",-1,1),new C("os",-1,1),new C("á",-1,1),new C("é",-1,2),new C("í",-1,1),new C("ó",-1,1)],b=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,1,17,4,10],f=new P;function _(){if(f.out_grouping(b,97,252)){for(;!f.in_grouping(b,97,252);){if(f.cursor>=f.limit)return!0;f.cursor++}return!1}return!0}function h(){var e,s=f.cursor;if(function(){if(f.in_grouping(b,97,252)){var e=f.cursor;if(_()){if(f.cursor=e,!f.in_grouping(b,97,252))return!0;for(;!f.out_grouping(b,97,252);){if(f.cursor>=f.limit)return!0;f.cursor++}}return!1}return!0}()){if(f.cursor=s,!f.out_grouping(b,97,252))return;if(e=f.cursor,_()){if(f.cursor=e,!f.in_grouping(b,97,252)||f.cursor>=f.limit)return;f.cursor++}}i=f.cursor}function v(){for(;!f.in_grouping(b,97,252);){if(f.cursor>=f.limit)return!1;f.cursor++}for(;!f.out_grouping(b,97,252);){if(f.cursor>=f.limit)return!1;f.cursor++}return!0}function p(){return i<=f.cursor}function g(){return r<=f.cursor}function k(e,s){if(!g())return!0;f.slice_del(),f.ket=f.cursor;var r=f.find_among_b(e,s);return r&&(f.bra=f.cursor,1==r&&g()&&f.slice_del()),!1}function y(e){return!g()||(f.slice_del(),f.ket=f.cursor,f.eq_s_b(2,e)&&(f.bra=f.cursor,g()&&f.slice_del()),!1)}function q(){var e;if(f.ket=f.cursor,e=f.find_among_b(c,46)){switch(f.bra=f.cursor,e){case 1:if(!g())return!1;f.slice_del();break;case 2:if(y("ic"))return!1;break;case 3:if(!g())return!1;f.slice_from("log");break;case 4:if(!g())return!1;f.slice_from("u");break;case 5:if(!g())return!1;f.slice_from("ente");break;case 6:if(!(n<=f.cursor))return!1;f.slice_del(),f.ket=f.cursor,(e=f.find_among_b(s,4))&&(f.bra=f.cursor,g()&&(f.slice_del(),1==e&&(f.ket=f.cursor,f.eq_s_b(2,"at")&&(f.bra=f.cursor,g()&&f.slice_del()))));break;case 7:if(k(u,3))return!1;break;case 8:if(k(w,3))return!1;break;case 9:if(y("at"))return!1}return!0}return!1}this.setCurrent=function(e){f.setCurrent(e)},this.getCurrent=function(){return f.getCurrent()},this.stem=function(){var e,s=f.cursor;return e=f.cursor,i=f.limit,r=n=i,h(),f.cursor=e,v()&&(n=f.cursor,v()&&(r=f.cursor)),f.limit_backward=s,f.cursor=f.limit,function(){var e;if(f.ket=f.cursor,f.find_among_b(t,13)&&(f.bra=f.cursor,(e=f.find_among_b(o,11))&&p()))switch(e){case 1:f.bra=f.cursor,f.slice_from("iendo");break;case 2:f.bra=f.cursor,f.slice_from("ando");break;case 3:f.bra=f.cursor,f.slice_from("ar");break;case 4:f.bra=f.cursor,f.slice_from("er");break;case 5:f.bra=f.cursor,f.slice_from("ir");break;case 6:f.slice_del();break;case 7:f.eq_s_b(1,"u")&&f.slice_del()}}(),f.cursor=f.limit,q()||(f.cursor=f.limit,function(){var e,s;if(f.cursor>=i&&(s=f.limit_backward,f.limit_backward=i,f.ket=f.cursor,e=f.find_among_b(m,12),f.limit_backward=s,e)){if(f.bra=f.cursor,1==e){if(!f.eq_s_b(1,"u"))return!1;f.slice_del()}return!0}return!1}()||(f.cursor=f.limit,function(){var e,s,r,n;if(f.cursor>=i&&(s=f.limit_backward,f.limit_backward=i,f.ket=f.cursor,e=f.find_among_b(l,96),f.limit_backward=s,e))switch(f.bra=f.cursor,e){case 1:r=f.limit-f.cursor,f.eq_s_b(1,"u")?(n=f.limit-f.cursor,f.eq_s_b(1,"g")?f.cursor=f.limit-n:f.cursor=f.limit-r):f.cursor=f.limit-r,f.bra=f.cursor;case 2:f.slice_del()}}())),f.cursor=f.limit,function(){var e,s;if(f.ket=f.cursor,e=f.find_among_b(d,8))switch(f.bra=f.cursor,e){case 1:p()&&f.slice_del();break;case 2:p()&&(f.slice_del(),f.ket=f.cursor,f.eq_s_b(1,"u")&&(f.bra=f.cursor,s=f.limit-f.cursor,f.eq_s_b(1,"g")&&(f.cursor=f.limit-s,p()&&f.slice_del())))}}(),f.cursor=f.limit_backward,function(){for(var e;;){if(f.bra=f.cursor,e=f.find_among(a,6))switch(f.ket=f.cursor,e){case 1:f.slice_from("a");continue;case 2:f.slice_from("e");continue;case 3:f.slice_from("i");continue;case 4:f.slice_from("o");continue;case 5:f.slice_from("u");continue;case 6:if(f.cursor>=f.limit)break;f.cursor++;continue}break}}(),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return s.setCurrent(e),s.stem(),s.getCurrent()}):(s.setCurrent(e),s.stem(),s.getCurrent())}),e.Pipeline.registerFunction(e.es.stemmer,"stemmer-es"),e.es.stopWordFilter=e.generateStopWordFilter("a al algo algunas algunos ante antes como con contra cual cuando de del desde donde durante e el ella ellas ellos en entre era erais eran eras eres es esa esas ese eso esos esta estaba estabais estaban estabas estad estada estadas estado estados estamos estando estar estaremos estará estarán estarás estaré estaréis estaría estaríais estaríamos estarían estarías estas este estemos esto estos estoy estuve estuviera estuvierais estuvieran estuvieras estuvieron estuviese estuvieseis estuviesen estuvieses estuvimos estuviste estuvisteis estuviéramos estuviésemos estuvo está estábamos estáis están estás esté estéis estén estés fue fuera fuerais fueran fueras fueron fuese fueseis fuesen fueses fui fuimos fuiste fuisteis fuéramos fuésemos ha habida habidas habido habidos habiendo habremos habrá habrán habrás habré habréis habría habríais habríamos habrían habrías habéis había habíais habíamos habían habías han has hasta hay haya hayamos hayan hayas hayáis he hemos hube hubiera hubierais hubieran hubieras hubieron hubiese hubieseis hubiesen hubieses hubimos hubiste hubisteis hubiéramos hubiésemos hubo la las le les lo los me mi mis mucho muchos muy más mí mía mías mío míos nada ni no nos nosotras nosotros nuestra nuestras nuestro nuestros o os otra otras otro otros para pero poco por porque que quien quienes qué se sea seamos sean seas seremos será serán serás seré seréis sería seríais seríamos serían serías seáis sido siendo sin sobre sois somos son soy su sus suya suyas suyo suyos sí también tanto te tendremos tendrá tendrán tendrás tendré tendréis tendría tendríais tendríamos tendrían tendrías tened tenemos tenga tengamos tengan tengas tengo tengáis tenida tenidas tenido tenidos teniendo tenéis tenía teníais teníamos tenían tenías ti tiene tienen tienes todo todos tu tus tuve tuviera tuvierais tuvieran tuvieras tuvieron tuviese tuvieseis tuviesen tuvieses tuvimos tuviste tuvisteis tuviéramos tuviésemos tuvo tuya tuyas tuyo tuyos tú un una uno unos vosotras vosotros vuestra vuestras vuestro vuestros y ya yo él éramos".split(" ")),e.Pipeline.registerFunction(e.es.stopWordFilter,"stopWordFilter-es")}}); \ No newline at end of file diff --git a/_static/javascripts/lunr/lunr.fi.js b/_static/javascripts/lunr/lunr.fi.js new file mode 100644 index 0000000000..2f9bf5aebd --- /dev/null +++ b/_static/javascripts/lunr/lunr.fi.js @@ -0,0 +1 @@ +!function(i,e){"function"==typeof define&&define.amd?define(e):"object"==typeof exports?module.exports=e():e()(i.lunr)}(this,function(){return function(i){if(void 0===i)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===i.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var v,C,e;i.fi=function(){this.pipeline.reset(),this.pipeline.add(i.fi.trimmer,i.fi.stopWordFilter,i.fi.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(i.fi.stemmer))},i.fi.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",i.fi.trimmer=i.trimmerSupport.generateTrimmer(i.fi.wordCharacters),i.Pipeline.registerFunction(i.fi.trimmer,"trimmer-fi"),i.fi.stemmer=(v=i.stemmerSupport.Among,C=i.stemmerSupport.SnowballProgram,e=new function(){var n,t,l,o,r=[new v("pa",-1,1),new v("sti",-1,2),new v("kaan",-1,1),new v("han",-1,1),new v("kin",-1,1),new v("hän",-1,1),new v("kään",-1,1),new v("ko",-1,1),new v("pä",-1,1),new v("kö",-1,1)],s=[new v("lla",-1,-1),new v("na",-1,-1),new v("ssa",-1,-1),new v("ta",-1,-1),new v("lta",3,-1),new v("sta",3,-1)],a=[new v("llä",-1,-1),new v("nä",-1,-1),new v("ssä",-1,-1),new v("tä",-1,-1),new v("ltä",3,-1),new v("stä",3,-1)],u=[new v("lle",-1,-1),new v("ine",-1,-1)],c=[new v("nsa",-1,3),new v("mme",-1,3),new v("nne",-1,3),new v("ni",-1,2),new v("si",-1,1),new v("an",-1,4),new v("en",-1,6),new v("än",-1,5),new v("nsä",-1,3)],i=[new v("aa",-1,-1),new v("ee",-1,-1),new v("ii",-1,-1),new v("oo",-1,-1),new v("uu",-1,-1),new v("ää",-1,-1),new v("öö",-1,-1)],m=[new v("a",-1,8),new v("lla",0,-1),new v("na",0,-1),new v("ssa",0,-1),new v("ta",0,-1),new v("lta",4,-1),new v("sta",4,-1),new v("tta",4,9),new v("lle",-1,-1),new v("ine",-1,-1),new v("ksi",-1,-1),new v("n",-1,7),new v("han",11,1),new v("den",11,-1,q),new v("seen",11,-1,j),new v("hen",11,2),new v("tten",11,-1,q),new v("hin",11,3),new v("siin",11,-1,q),new v("hon",11,4),new v("hän",11,5),new v("hön",11,6),new v("ä",-1,8),new v("llä",22,-1),new v("nä",22,-1),new v("ssä",22,-1),new v("tä",22,-1),new v("ltä",26,-1),new v("stä",26,-1),new v("ttä",26,9)],w=[new v("eja",-1,-1),new v("mma",-1,1),new v("imma",1,-1),new v("mpa",-1,1),new v("impa",3,-1),new v("mmi",-1,1),new v("immi",5,-1),new v("mpi",-1,1),new v("impi",7,-1),new v("ejä",-1,-1),new v("mmä",-1,1),new v("immä",10,-1),new v("mpä",-1,1),new v("impä",12,-1)],_=[new v("i",-1,-1),new v("j",-1,-1)],k=[new v("mma",-1,1),new v("imma",0,-1)],b=[17,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8],d=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32],e=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32],f=[17,97,24,1,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32],h=new C;function p(){for(var i;i=h.cursor,!h.in_grouping(d,97,246);){if((h.cursor=i)>=h.limit)return!0;h.cursor++}for(h.cursor=i;!h.out_grouping(d,97,246);){if(h.cursor>=h.limit)return!0;h.cursor++}return!1}function g(){var i,e;if(h.cursor>=o)if(e=h.limit_backward,h.limit_backward=o,h.ket=h.cursor,i=h.find_among_b(r,10)){switch(h.bra=h.cursor,h.limit_backward=e,i){case 1:if(!h.in_grouping_b(f,97,246))return;break;case 2:if(!(l<=h.cursor))return}h.slice_del()}else h.limit_backward=e}function j(){return h.find_among_b(i,7)}function q(){return h.eq_s_b(1,"i")&&h.in_grouping_b(e,97,246)}this.setCurrent=function(i){h.setCurrent(i)},this.getCurrent=function(){return h.getCurrent()},this.stem=function(){var i,e=h.cursor;return o=h.limit,l=o,p()||(o=h.cursor,p()||(l=h.cursor)),n=!1,h.limit_backward=e,h.cursor=h.limit,g(),h.cursor=h.limit,function(){var i,e,r;if(h.cursor>=o)if(e=h.limit_backward,h.limit_backward=o,h.ket=h.cursor,i=h.find_among_b(c,9))switch(h.bra=h.cursor,h.limit_backward=e,i){case 1:r=h.limit-h.cursor,h.eq_s_b(1,"k")||(h.cursor=h.limit-r,h.slice_del());break;case 2:h.slice_del(),h.ket=h.cursor,h.eq_s_b(3,"kse")&&(h.bra=h.cursor,h.slice_from("ksi"));break;case 3:h.slice_del();break;case 4:h.find_among_b(s,6)&&h.slice_del();break;case 5:h.find_among_b(a,6)&&h.slice_del();break;case 6:h.find_among_b(u,2)&&h.slice_del()}else h.limit_backward=e}(),h.cursor=h.limit,function(){var i,e,r;if(h.cursor>=o)if(e=h.limit_backward,h.limit_backward=o,h.ket=h.cursor,i=h.find_among_b(m,30)){switch(h.bra=h.cursor,h.limit_backward=e,i){case 1:if(!h.eq_s_b(1,"a"))return;break;case 2:case 9:if(!h.eq_s_b(1,"e"))return;break;case 3:if(!h.eq_s_b(1,"i"))return;break;case 4:if(!h.eq_s_b(1,"o"))return;break;case 5:if(!h.eq_s_b(1,"ä"))return;break;case 6:if(!h.eq_s_b(1,"ö"))return;break;case 7:if(r=h.limit-h.cursor,!j()&&(h.cursor=h.limit-r,!h.eq_s_b(2,"ie"))){h.cursor=h.limit-r;break}if(h.cursor=h.limit-r,h.cursor<=h.limit_backward){h.cursor=h.limit-r;break}h.cursor--,h.bra=h.cursor;break;case 8:if(!h.in_grouping_b(d,97,246)||!h.out_grouping_b(d,97,246))return}h.slice_del(),n=!0}else h.limit_backward=e}(),h.cursor=h.limit,function(){var i,e,r;if(h.cursor>=l)if(e=h.limit_backward,h.limit_backward=l,h.ket=h.cursor,i=h.find_among_b(w,14)){if(h.bra=h.cursor,h.limit_backward=e,1==i){if(r=h.limit-h.cursor,h.eq_s_b(2,"po"))return;h.cursor=h.limit-r}h.slice_del()}else h.limit_backward=e}(),h.cursor=h.limit,h.cursor=(n?h.cursor>=o&&(i=h.limit_backward,h.limit_backward=o,h.ket=h.cursor,h.find_among_b(_,2)?(h.bra=h.cursor,h.limit_backward=i,h.slice_del()):h.limit_backward=i):(h.cursor=h.limit,function(){var i,e,r,n,t,s;if(h.cursor>=o){if(e=h.limit_backward,h.limit_backward=o,h.ket=h.cursor,h.eq_s_b(1,"t")&&(h.bra=h.cursor,r=h.limit-h.cursor,h.in_grouping_b(d,97,246)&&(h.cursor=h.limit-r,h.slice_del(),h.limit_backward=e,n=h.limit-h.cursor,h.cursor>=l&&(h.cursor=l,t=h.limit_backward,h.limit_backward=h.cursor,h.cursor=h.limit-n,h.ket=h.cursor,i=h.find_among_b(k,2))))){if(h.bra=h.cursor,h.limit_backward=t,1==i){if(s=h.limit-h.cursor,h.eq_s_b(2,"po"))return;h.cursor=h.limit-s}return h.slice_del()}h.limit_backward=e}}()),h.limit),function(){var i,e,r,n;if(h.cursor>=o){for(i=h.limit_backward,h.limit_backward=o,e=h.limit-h.cursor,j()&&(h.cursor=h.limit-e,h.ket=h.cursor,h.cursor>h.limit_backward&&(h.cursor--,h.bra=h.cursor,h.slice_del())),h.cursor=h.limit-e,h.ket=h.cursor,h.in_grouping_b(b,97,228)&&(h.bra=h.cursor,h.out_grouping_b(d,97,246)&&h.slice_del()),h.cursor=h.limit-e,h.ket=h.cursor,h.eq_s_b(1,"j")&&(h.bra=h.cursor,r=h.limit-h.cursor,h.eq_s_b(1,"o")?h.slice_del():(h.cursor=h.limit-r,h.eq_s_b(1,"u")&&h.slice_del())),h.cursor=h.limit-e,h.ket=h.cursor,h.eq_s_b(1,"o")&&(h.bra=h.cursor,h.eq_s_b(1,"j")&&h.slice_del()),h.cursor=h.limit-e,h.limit_backward=i;;){if(n=h.limit-h.cursor,h.out_grouping_b(d,97,246)){h.cursor=h.limit-n;break}if(h.cursor=h.limit-n,h.cursor<=h.limit_backward)return;h.cursor--}h.ket=h.cursor,h.cursor>h.limit_backward&&(h.cursor--,h.bra=h.cursor,t=h.slice_to(),h.eq_v_b(t)&&h.slice_del())}}(),!0}},function(i){return"function"==typeof i.update?i.update(function(i){return e.setCurrent(i),e.stem(),e.getCurrent()}):(e.setCurrent(i),e.stem(),e.getCurrent())}),i.Pipeline.registerFunction(i.fi.stemmer,"stemmer-fi"),i.fi.stopWordFilter=i.generateStopWordFilter("ei eivät emme en et ette että he heidän heidät heihin heille heillä heiltä heissä heistä heitä hän häneen hänelle hänellä häneltä hänen hänessä hänestä hänet häntä itse ja johon joiden joihin joiksi joilla joille joilta joina joissa joista joita joka joksi jolla jolle jolta jona jonka jos jossa josta jota jotka kanssa keiden keihin keiksi keille keillä keiltä keinä keissä keistä keitä keneen keneksi kenelle kenellä keneltä kenen kenenä kenessä kenestä kenet ketkä ketkä ketä koska kuin kuka kun me meidän meidät meihin meille meillä meiltä meissä meistä meitä mihin miksi mikä mille millä miltä minkä minkä minua minulla minulle minulta minun minussa minusta minut minuun minä minä missä mistä mitkä mitä mukaan mutta ne niiden niihin niiksi niille niillä niiltä niin niin niinä niissä niistä niitä noiden noihin noiksi noilla noille noilta noin noina noissa noista noita nuo nyt näiden näihin näiksi näille näillä näiltä näinä näissä näistä näitä nämä ole olemme olen olet olette oli olimme olin olisi olisimme olisin olisit olisitte olisivat olit olitte olivat olla olleet ollut on ovat poikki se sekä sen siihen siinä siitä siksi sille sillä sillä siltä sinua sinulla sinulle sinulta sinun sinussa sinusta sinut sinuun sinä sinä sitä tai te teidän teidät teihin teille teillä teiltä teissä teistä teitä tuo tuohon tuoksi tuolla tuolle tuolta tuon tuona tuossa tuosta tuota tähän täksi tälle tällä tältä tämä tämän tänä tässä tästä tätä vaan vai vaikka yli".split(" ")),i.Pipeline.registerFunction(i.fi.stopWordFilter,"stopWordFilter-fi")}}); \ No newline at end of file diff --git a/_static/javascripts/lunr/lunr.fr.js b/_static/javascripts/lunr/lunr.fr.js new file mode 100644 index 0000000000..078d0cab70 --- /dev/null +++ b/_static/javascripts/lunr/lunr.fr.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r,y,s;e.fr=function(){this.pipeline.reset(),this.pipeline.add(e.fr.trimmer,e.fr.stopWordFilter,e.fr.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.fr.stemmer))},e.fr.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.fr.trimmer=e.trimmerSupport.generateTrimmer(e.fr.wordCharacters),e.Pipeline.registerFunction(e.fr.trimmer,"trimmer-fr"),e.fr.stemmer=(r=e.stemmerSupport.Among,y=e.stemmerSupport.SnowballProgram,s=new function(){var s,i,t,n=[new r("col",-1,-1),new r("par",-1,-1),new r("tap",-1,-1)],u=[new r("",-1,4),new r("I",0,1),new r("U",0,2),new r("Y",0,3)],o=[new r("iqU",-1,3),new r("abl",-1,3),new r("Ièr",-1,4),new r("ièr",-1,4),new r("eus",-1,2),new r("iv",-1,1)],c=[new r("ic",-1,2),new r("abil",-1,1),new r("iv",-1,3)],a=[new r("iqUe",-1,1),new r("atrice",-1,2),new r("ance",-1,1),new r("ence",-1,5),new r("logie",-1,3),new r("able",-1,1),new r("isme",-1,1),new r("euse",-1,11),new r("iste",-1,1),new r("ive",-1,8),new r("if",-1,8),new r("usion",-1,4),new r("ation",-1,2),new r("ution",-1,4),new r("ateur",-1,2),new r("iqUes",-1,1),new r("atrices",-1,2),new r("ances",-1,1),new r("ences",-1,5),new r("logies",-1,3),new r("ables",-1,1),new r("ismes",-1,1),new r("euses",-1,11),new r("istes",-1,1),new r("ives",-1,8),new r("ifs",-1,8),new r("usions",-1,4),new r("ations",-1,2),new r("utions",-1,4),new r("ateurs",-1,2),new r("ments",-1,15),new r("ements",30,6),new r("issements",31,12),new r("ités",-1,7),new r("ment",-1,15),new r("ement",34,6),new r("issement",35,12),new r("amment",34,13),new r("emment",34,14),new r("aux",-1,10),new r("eaux",39,9),new r("eux",-1,1),new r("ité",-1,7)],l=[new r("ira",-1,1),new r("ie",-1,1),new r("isse",-1,1),new r("issante",-1,1),new r("i",-1,1),new r("irai",4,1),new r("ir",-1,1),new r("iras",-1,1),new r("ies",-1,1),new r("îmes",-1,1),new r("isses",-1,1),new r("issantes",-1,1),new r("îtes",-1,1),new r("is",-1,1),new r("irais",13,1),new r("issais",13,1),new r("irions",-1,1),new r("issions",-1,1),new r("irons",-1,1),new r("issons",-1,1),new r("issants",-1,1),new r("it",-1,1),new r("irait",21,1),new r("issait",21,1),new r("issant",-1,1),new r("iraIent",-1,1),new r("issaIent",-1,1),new r("irent",-1,1),new r("issent",-1,1),new r("iront",-1,1),new r("ît",-1,1),new r("iriez",-1,1),new r("issiez",-1,1),new r("irez",-1,1),new r("issez",-1,1)],w=[new r("a",-1,3),new r("era",0,2),new r("asse",-1,3),new r("ante",-1,3),new r("ée",-1,2),new r("ai",-1,3),new r("erai",5,2),new r("er",-1,2),new r("as",-1,3),new r("eras",8,2),new r("âmes",-1,3),new r("asses",-1,3),new r("antes",-1,3),new r("âtes",-1,3),new r("ées",-1,2),new r("ais",-1,3),new r("erais",15,2),new r("ions",-1,1),new r("erions",17,2),new r("assions",17,3),new r("erons",-1,2),new r("ants",-1,3),new r("és",-1,2),new r("ait",-1,3),new r("erait",23,2),new r("ant",-1,3),new r("aIent",-1,3),new r("eraIent",26,2),new r("èrent",-1,2),new r("assent",-1,3),new r("eront",-1,2),new r("ât",-1,3),new r("ez",-1,2),new r("iez",32,2),new r("eriez",33,2),new r("assiez",33,3),new r("erez",32,2),new r("é",-1,2)],f=[new r("e",-1,3),new r("Ière",0,2),new r("ière",0,2),new r("ion",-1,1),new r("Ier",-1,2),new r("ier",-1,2),new r("ë",-1,4)],m=[new r("ell",-1,-1),new r("eill",-1,-1),new r("enn",-1,-1),new r("onn",-1,-1),new r("ett",-1,-1)],_=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,128,130,103,8,5],b=[1,65,20,0,0,0,0,0,0,0,0,0,0,0,0,0,128],d=new y;function k(e,r,s){return!(!d.eq_s(1,e)||(d.ket=d.cursor,!d.in_grouping(_,97,251)))&&(d.slice_from(r),d.cursor=s,!0)}function p(e,r,s){return!!d.eq_s(1,e)&&(d.ket=d.cursor,d.slice_from(r),d.cursor=s,!0)}function g(){for(;!d.in_grouping(_,97,251);){if(d.cursor>=d.limit)return!0;d.cursor++}for(;!d.out_grouping(_,97,251);){if(d.cursor>=d.limit)return!0;d.cursor++}return!1}function q(){return t<=d.cursor}function v(){return i<=d.cursor}function h(){return s<=d.cursor}function z(){if(!function(){var e,r;if(d.ket=d.cursor,e=d.find_among_b(a,43)){switch(d.bra=d.cursor,e){case 1:if(!h())return!1;d.slice_del();break;case 2:if(!h())return!1;d.slice_del(),d.ket=d.cursor,d.eq_s_b(2,"ic")&&(d.bra=d.cursor,h()?d.slice_del():d.slice_from("iqU"));break;case 3:if(!h())return!1;d.slice_from("log");break;case 4:if(!h())return!1;d.slice_from("u");break;case 5:if(!h())return!1;d.slice_from("ent");break;case 6:if(!q())return!1;if(d.slice_del(),d.ket=d.cursor,e=d.find_among_b(o,6))switch(d.bra=d.cursor,e){case 1:h()&&(d.slice_del(),d.ket=d.cursor,d.eq_s_b(2,"at")&&(d.bra=d.cursor,h()&&d.slice_del()));break;case 2:h()?d.slice_del():v()&&d.slice_from("eux");break;case 3:h()&&d.slice_del();break;case 4:q()&&d.slice_from("i")}break;case 7:if(!h())return!1;if(d.slice_del(),d.ket=d.cursor,e=d.find_among_b(c,3))switch(d.bra=d.cursor,e){case 1:h()?d.slice_del():d.slice_from("abl");break;case 2:h()?d.slice_del():d.slice_from("iqU");break;case 3:h()&&d.slice_del()}break;case 8:if(!h())return!1;if(d.slice_del(),d.ket=d.cursor,d.eq_s_b(2,"at")&&(d.bra=d.cursor,h()&&(d.slice_del(),d.ket=d.cursor,d.eq_s_b(2,"ic")))){d.bra=d.cursor,h()?d.slice_del():d.slice_from("iqU");break}break;case 9:d.slice_from("eau");break;case 10:if(!v())return!1;d.slice_from("al");break;case 11:if(h())d.slice_del();else{if(!v())return!1;d.slice_from("eux")}break;case 12:if(!v()||!d.out_grouping_b(_,97,251))return!1;d.slice_del();break;case 13:return q()&&d.slice_from("ant"),!1;case 14:return q()&&d.slice_from("ent"),!1;case 15:return r=d.limit-d.cursor,d.in_grouping_b(_,97,251)&&q()&&(d.cursor=d.limit-r,d.slice_del()),!1}return!0}return!1}()&&(d.cursor=d.limit,!function(){var e,r;if(d.cursor=t){if(s=d.limit_backward,d.limit_backward=t,d.ket=d.cursor,e=d.find_among_b(f,7))switch(d.bra=d.cursor,e){case 1:if(h()){if(i=d.limit-d.cursor,!d.eq_s_b(1,"s")&&(d.cursor=d.limit-i,!d.eq_s_b(1,"t")))break;d.slice_del()}break;case 2:d.slice_from("i");break;case 3:d.slice_del();break;case 4:d.eq_s_b(2,"gu")&&d.slice_del()}d.limit_backward=s}}();d.cursor=d.limit,d.ket=d.cursor,d.eq_s_b(1,"Y")?(d.bra=d.cursor,d.slice_from("i")):(d.cursor=d.limit,d.eq_s_b(1,"ç")&&(d.bra=d.cursor,d.slice_from("c")))}this.setCurrent=function(e){d.setCurrent(e)},this.getCurrent=function(){return d.getCurrent()},this.stem=function(){var e,r=d.cursor;return function(){for(var e,r;;){if(e=d.cursor,d.in_grouping(_,97,251)){if(d.bra=d.cursor,r=d.cursor,k("u","U",e))continue;if(d.cursor=r,k("i","I",e))continue;if(d.cursor=r,p("y","Y",e))continue}if(d.cursor=e,!k("y","Y",d.bra=e)){if(d.cursor=e,d.eq_s(1,"q")&&(d.bra=d.cursor,p("u","U",e)))continue;if((d.cursor=e)>=d.limit)return;d.cursor++}}}(),d.cursor=r,function(){var e=d.cursor;if(t=d.limit,s=i=t,d.in_grouping(_,97,251)&&d.in_grouping(_,97,251)&&d.cursor=d.limit){d.cursor=t;break}d.cursor++}while(!d.in_grouping(_,97,251))}t=d.cursor,d.cursor=e,g()||(i=d.cursor,g()||(s=d.cursor))}(),d.limit_backward=r,d.cursor=d.limit,z(),d.cursor=d.limit,e=d.limit-d.cursor,d.find_among_b(m,5)&&(d.cursor=d.limit-e,d.ket=d.cursor,d.cursor>d.limit_backward&&(d.cursor--,d.bra=d.cursor,d.slice_del())),d.cursor=d.limit,function(){for(var e,r=1;d.out_grouping_b(_,97,251);)r--;if(r<=0){if(d.ket=d.cursor,e=d.limit-d.cursor,!d.eq_s_b(1,"é")&&(d.cursor=d.limit-e,!d.eq_s_b(1,"è")))return;d.bra=d.cursor,d.slice_from("e")}}(),d.cursor=d.limit_backward,function(){for(var e,r;r=d.cursor,d.bra=r,e=d.find_among(u,4);)switch(d.ket=d.cursor,e){case 1:d.slice_from("i");break;case 2:d.slice_from("u");break;case 3:d.slice_from("y");break;case 4:if(d.cursor>=d.limit)return;d.cursor++}}(),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return s.setCurrent(e),s.stem(),s.getCurrent()}):(s.setCurrent(e),s.stem(),s.getCurrent())}),e.Pipeline.registerFunction(e.fr.stemmer,"stemmer-fr"),e.fr.stopWordFilter=e.generateStopWordFilter("ai aie aient aies ait as au aura aurai auraient aurais aurait auras aurez auriez aurions aurons auront aux avaient avais avait avec avez aviez avions avons ayant ayez ayons c ce ceci celà ces cet cette d dans de des du elle en es est et eu eue eues eurent eus eusse eussent eusses eussiez eussions eut eux eûmes eût eûtes furent fus fusse fussent fusses fussiez fussions fut fûmes fût fûtes ici il ils j je l la le les leur leurs lui m ma mais me mes moi mon même n ne nos notre nous on ont ou par pas pour qu que quel quelle quelles quels qui s sa sans se sera serai seraient serais serait seras serez seriez serions serons seront ses soi soient sois soit sommes son sont soyez soyons suis sur t ta te tes toi ton tu un une vos votre vous y à étaient étais était étant étiez étions été étée étées étés êtes".split(" ")),e.Pipeline.registerFunction(e.fr.stopWordFilter,"stopWordFilter-fr")}}); \ No newline at end of file diff --git a/_static/javascripts/lunr/lunr.hu.js b/_static/javascripts/lunr/lunr.hu.js new file mode 100644 index 0000000000..56a4b0dc19 --- /dev/null +++ b/_static/javascripts/lunr/lunr.hu.js @@ -0,0 +1 @@ +!function(e,n){"function"==typeof define&&define.amd?define(n):"object"==typeof exports?module.exports=n():n()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var p,_,n;e.hu=function(){this.pipeline.reset(),this.pipeline.add(e.hu.trimmer,e.hu.stopWordFilter,e.hu.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.hu.stemmer))},e.hu.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.hu.trimmer=e.trimmerSupport.generateTrimmer(e.hu.wordCharacters),e.Pipeline.registerFunction(e.hu.trimmer,"trimmer-hu"),e.hu.stemmer=(p=e.stemmerSupport.Among,_=e.stemmerSupport.SnowballProgram,n=new function(){var r,i=[new p("cs",-1,-1),new p("dzs",-1,-1),new p("gy",-1,-1),new p("ly",-1,-1),new p("ny",-1,-1),new p("sz",-1,-1),new p("ty",-1,-1),new p("zs",-1,-1)],n=[new p("á",-1,1),new p("é",-1,2)],a=[new p("bb",-1,-1),new p("cc",-1,-1),new p("dd",-1,-1),new p("ff",-1,-1),new p("gg",-1,-1),new p("jj",-1,-1),new p("kk",-1,-1),new p("ll",-1,-1),new p("mm",-1,-1),new p("nn",-1,-1),new p("pp",-1,-1),new p("rr",-1,-1),new p("ccs",-1,-1),new p("ss",-1,-1),new p("zzs",-1,-1),new p("tt",-1,-1),new p("vv",-1,-1),new p("ggy",-1,-1),new p("lly",-1,-1),new p("nny",-1,-1),new p("tty",-1,-1),new p("ssz",-1,-1),new p("zz",-1,-1)],t=[new p("al",-1,1),new p("el",-1,2)],e=[new p("ba",-1,-1),new p("ra",-1,-1),new p("be",-1,-1),new p("re",-1,-1),new p("ig",-1,-1),new p("nak",-1,-1),new p("nek",-1,-1),new p("val",-1,-1),new p("vel",-1,-1),new p("ul",-1,-1),new p("nál",-1,-1),new p("nél",-1,-1),new p("ból",-1,-1),new p("ról",-1,-1),new p("tól",-1,-1),new p("bõl",-1,-1),new p("rõl",-1,-1),new p("tõl",-1,-1),new p("ül",-1,-1),new p("n",-1,-1),new p("an",19,-1),new p("ban",20,-1),new p("en",19,-1),new p("ben",22,-1),new p("képpen",22,-1),new p("on",19,-1),new p("ön",19,-1),new p("képp",-1,-1),new p("kor",-1,-1),new p("t",-1,-1),new p("at",29,-1),new p("et",29,-1),new p("ként",29,-1),new p("anként",32,-1),new p("enként",32,-1),new p("onként",32,-1),new p("ot",29,-1),new p("ért",29,-1),new p("öt",29,-1),new p("hez",-1,-1),new p("hoz",-1,-1),new p("höz",-1,-1),new p("vá",-1,-1),new p("vé",-1,-1)],s=[new p("án",-1,2),new p("én",-1,1),new p("ánként",-1,3)],c=[new p("stul",-1,2),new p("astul",0,1),new p("ástul",0,3),new p("stül",-1,2),new p("estül",3,1),new p("éstül",3,4)],w=[new p("á",-1,1),new p("é",-1,2)],o=[new p("k",-1,7),new p("ak",0,4),new p("ek",0,6),new p("ok",0,5),new p("ák",0,1),new p("ék",0,2),new p("ök",0,3)],l=[new p("éi",-1,7),new p("áéi",0,6),new p("ééi",0,5),new p("é",-1,9),new p("ké",3,4),new p("aké",4,1),new p("eké",4,1),new p("oké",4,1),new p("áké",4,3),new p("éké",4,2),new p("öké",4,1),new p("éé",3,8)],u=[new p("a",-1,18),new p("ja",0,17),new p("d",-1,16),new p("ad",2,13),new p("ed",2,13),new p("od",2,13),new p("ád",2,14),new p("éd",2,15),new p("öd",2,13),new p("e",-1,18),new p("je",9,17),new p("nk",-1,4),new p("unk",11,1),new p("ánk",11,2),new p("énk",11,3),new p("ünk",11,1),new p("uk",-1,8),new p("juk",16,7),new p("ájuk",17,5),new p("ük",-1,8),new p("jük",19,7),new p("éjük",20,6),new p("m",-1,12),new p("am",22,9),new p("em",22,9),new p("om",22,9),new p("ám",22,10),new p("ém",22,11),new p("o",-1,18),new p("á",-1,19),new p("é",-1,20)],m=[new p("id",-1,10),new p("aid",0,9),new p("jaid",1,6),new p("eid",0,9),new p("jeid",3,6),new p("áid",0,7),new p("éid",0,8),new p("i",-1,15),new p("ai",7,14),new p("jai",8,11),new p("ei",7,14),new p("jei",10,11),new p("ái",7,12),new p("éi",7,13),new p("itek",-1,24),new p("eitek",14,21),new p("jeitek",15,20),new p("éitek",14,23),new p("ik",-1,29),new p("aik",18,26),new p("jaik",19,25),new p("eik",18,26),new p("jeik",21,25),new p("áik",18,27),new p("éik",18,28),new p("ink",-1,20),new p("aink",25,17),new p("jaink",26,16),new p("eink",25,17),new p("jeink",28,16),new p("áink",25,18),new p("éink",25,19),new p("aitok",-1,21),new p("jaitok",32,20),new p("áitok",-1,22),new p("im",-1,5),new p("aim",35,4),new p("jaim",36,1),new p("eim",35,4),new p("jeim",38,1),new p("áim",35,2),new p("éim",35,3)],k=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,1,17,52,14],f=new _;function b(){return r<=f.cursor}function d(){var e=f.limit-f.cursor;return!!f.find_among_b(a,23)&&(f.cursor=f.limit-e,!0)}function g(){if(f.cursor>f.limit_backward){f.cursor--,f.ket=f.cursor;var e=f.cursor-1;f.limit_backward<=e&&e<=f.limit&&(f.cursor=e,f.bra=e,f.slice_del())}}function h(){f.ket=f.cursor,f.find_among_b(e,44)&&(f.bra=f.cursor,b()&&(f.slice_del(),function(){var e;if(f.ket=f.cursor,(e=f.find_among_b(n,2))&&(f.bra=f.cursor,b()))switch(e){case 1:f.slice_from("a");break;case 2:f.slice_from("e")}}()))}this.setCurrent=function(e){f.setCurrent(e)},this.getCurrent=function(){return f.getCurrent()},this.stem=function(){var e=f.cursor;return function(){var e,n=f.cursor;if(r=f.limit,f.in_grouping(k,97,252))for(;;){if(e=f.cursor,f.out_grouping(k,97,252))return f.cursor=e,f.find_among(i,8)||(f.cursor=e)=f.limit)return r=e;f.cursor++}if(f.cursor=n,f.out_grouping(k,97,252)){for(;!f.in_grouping(k,97,252);){if(f.cursor>=f.limit)return;f.cursor++}r=f.cursor}}(),f.limit_backward=e,f.cursor=f.limit,function(){var e;if(f.ket=f.cursor,(e=f.find_among_b(t,2))&&(f.bra=f.cursor,b())){if((1==e||2==e)&&!d())return;f.slice_del(),g()}}(),f.cursor=f.limit,h(),f.cursor=f.limit,function(){var e;if(f.ket=f.cursor,(e=f.find_among_b(s,3))&&(f.bra=f.cursor,b()))switch(e){case 1:f.slice_from("e");break;case 2:case 3:f.slice_from("a")}}(),f.cursor=f.limit,function(){var e;if(f.ket=f.cursor,(e=f.find_among_b(c,6))&&(f.bra=f.cursor,b()))switch(e){case 1:case 2:f.slice_del();break;case 3:f.slice_from("a");break;case 4:f.slice_from("e")}}(),f.cursor=f.limit,function(){var e;if(f.ket=f.cursor,(e=f.find_among_b(w,2))&&(f.bra=f.cursor,b())){if((1==e||2==e)&&!d())return;f.slice_del(),g()}}(),f.cursor=f.limit,function(){var e;if(f.ket=f.cursor,(e=f.find_among_b(l,12))&&(f.bra=f.cursor,b()))switch(e){case 1:case 4:case 7:case 9:f.slice_del();break;case 2:case 5:case 8:f.slice_from("e");break;case 3:case 6:f.slice_from("a")}}(),f.cursor=f.limit,function(){var e;if(f.ket=f.cursor,(e=f.find_among_b(u,31))&&(f.bra=f.cursor,b()))switch(e){case 1:case 4:case 7:case 8:case 9:case 12:case 13:case 16:case 17:case 18:f.slice_del();break;case 2:case 5:case 10:case 14:case 19:f.slice_from("a");break;case 3:case 6:case 11:case 15:case 20:f.slice_from("e")}}(),f.cursor=f.limit,function(){var e;if(f.ket=f.cursor,(e=f.find_among_b(m,42))&&(f.bra=f.cursor,b()))switch(e){case 1:case 4:case 5:case 6:case 9:case 10:case 11:case 14:case 15:case 16:case 17:case 20:case 21:case 24:case 25:case 26:case 29:f.slice_del();break;case 2:case 7:case 12:case 18:case 22:case 27:f.slice_from("a");break;case 3:case 8:case 13:case 19:case 23:case 28:f.slice_from("e")}}(),f.cursor=f.limit,function(){var e;if(f.ket=f.cursor,(e=f.find_among_b(o,7))&&(f.bra=f.cursor,b()))switch(e){case 1:f.slice_from("a");break;case 2:f.slice_from("e");break;case 3:case 4:case 5:case 6:case 7:f.slice_del()}}(),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}),e.Pipeline.registerFunction(e.hu.stemmer,"stemmer-hu"),e.hu.stopWordFilter=e.generateStopWordFilter("a abban ahhoz ahogy ahol aki akik akkor alatt amely amelyek amelyekben amelyeket amelyet amelynek ami amikor amit amolyan amíg annak arra arról az azok azon azonban azt aztán azután azzal azért be belül benne bár cikk cikkek cikkeket csak de e ebben eddig egy egyes egyetlen egyik egyre egyéb egész ehhez ekkor el ellen elsõ elég elõ elõször elõtt emilyen ennek erre ez ezek ezen ezt ezzel ezért fel felé hanem hiszen hogy hogyan igen ill ill. illetve ilyen ilyenkor ismét ison itt jobban jó jól kell kellett keressünk keresztül ki kívül között közül legalább legyen lehet lehetett lenne lenni lesz lett maga magát majd majd meg mellett mely melyek mert mi mikor milyen minden mindenki mindent mindig mint mintha mit mivel miért most már más másik még míg nagy nagyobb nagyon ne nekem neki nem nincs néha néhány nélkül olyan ott pedig persze rá s saját sem semmi sok sokat sokkal szemben szerint szinte számára talán tehát teljes tovább továbbá több ugyanis utolsó után utána vagy vagyis vagyok valaki valami valamint való van vannak vele vissza viszont volna volt voltak voltam voltunk által általában át én éppen és így õ õk õket össze úgy új újabb újra".split(" ")),e.Pipeline.registerFunction(e.hu.stopWordFilter,"stopWordFilter-hu")}}); \ No newline at end of file diff --git a/_static/javascripts/lunr/lunr.it.js b/_static/javascripts/lunr/lunr.it.js new file mode 100644 index 0000000000..50dddaa04b --- /dev/null +++ b/_static/javascripts/lunr/lunr.it.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var z,P,r;e.it=function(){this.pipeline.reset(),this.pipeline.add(e.it.trimmer,e.it.stopWordFilter,e.it.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.it.stemmer))},e.it.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.it.trimmer=e.trimmerSupport.generateTrimmer(e.it.wordCharacters),e.Pipeline.registerFunction(e.it.trimmer,"trimmer-it"),e.it.stemmer=(z=e.stemmerSupport.Among,P=e.stemmerSupport.SnowballProgram,r=new function(){var o,t,s,a=[new z("",-1,7),new z("qu",0,6),new z("á",0,1),new z("é",0,2),new z("í",0,3),new z("ó",0,4),new z("ú",0,5)],u=[new z("",-1,3),new z("I",0,1),new z("U",0,2)],c=[new z("la",-1,-1),new z("cela",0,-1),new z("gliela",0,-1),new z("mela",0,-1),new z("tela",0,-1),new z("vela",0,-1),new z("le",-1,-1),new z("cele",6,-1),new z("gliele",6,-1),new z("mele",6,-1),new z("tele",6,-1),new z("vele",6,-1),new z("ne",-1,-1),new z("cene",12,-1),new z("gliene",12,-1),new z("mene",12,-1),new z("sene",12,-1),new z("tene",12,-1),new z("vene",12,-1),new z("ci",-1,-1),new z("li",-1,-1),new z("celi",20,-1),new z("glieli",20,-1),new z("meli",20,-1),new z("teli",20,-1),new z("veli",20,-1),new z("gli",20,-1),new z("mi",-1,-1),new z("si",-1,-1),new z("ti",-1,-1),new z("vi",-1,-1),new z("lo",-1,-1),new z("celo",31,-1),new z("glielo",31,-1),new z("melo",31,-1),new z("telo",31,-1),new z("velo",31,-1)],w=[new z("ando",-1,1),new z("endo",-1,1),new z("ar",-1,2),new z("er",-1,2),new z("ir",-1,2)],r=[new z("ic",-1,-1),new z("abil",-1,-1),new z("os",-1,-1),new z("iv",-1,1)],n=[new z("ic",-1,1),new z("abil",-1,1),new z("iv",-1,1)],i=[new z("ica",-1,1),new z("logia",-1,3),new z("osa",-1,1),new z("ista",-1,1),new z("iva",-1,9),new z("anza",-1,1),new z("enza",-1,5),new z("ice",-1,1),new z("atrice",7,1),new z("iche",-1,1),new z("logie",-1,3),new z("abile",-1,1),new z("ibile",-1,1),new z("usione",-1,4),new z("azione",-1,2),new z("uzione",-1,4),new z("atore",-1,2),new z("ose",-1,1),new z("ante",-1,1),new z("mente",-1,1),new z("amente",19,7),new z("iste",-1,1),new z("ive",-1,9),new z("anze",-1,1),new z("enze",-1,5),new z("ici",-1,1),new z("atrici",25,1),new z("ichi",-1,1),new z("abili",-1,1),new z("ibili",-1,1),new z("ismi",-1,1),new z("usioni",-1,4),new z("azioni",-1,2),new z("uzioni",-1,4),new z("atori",-1,2),new z("osi",-1,1),new z("anti",-1,1),new z("amenti",-1,6),new z("imenti",-1,6),new z("isti",-1,1),new z("ivi",-1,9),new z("ico",-1,1),new z("ismo",-1,1),new z("oso",-1,1),new z("amento",-1,6),new z("imento",-1,6),new z("ivo",-1,9),new z("ità",-1,8),new z("istà",-1,1),new z("istè",-1,1),new z("istì",-1,1)],l=[new z("isca",-1,1),new z("enda",-1,1),new z("ata",-1,1),new z("ita",-1,1),new z("uta",-1,1),new z("ava",-1,1),new z("eva",-1,1),new z("iva",-1,1),new z("erebbe",-1,1),new z("irebbe",-1,1),new z("isce",-1,1),new z("ende",-1,1),new z("are",-1,1),new z("ere",-1,1),new z("ire",-1,1),new z("asse",-1,1),new z("ate",-1,1),new z("avate",16,1),new z("evate",16,1),new z("ivate",16,1),new z("ete",-1,1),new z("erete",20,1),new z("irete",20,1),new z("ite",-1,1),new z("ereste",-1,1),new z("ireste",-1,1),new z("ute",-1,1),new z("erai",-1,1),new z("irai",-1,1),new z("isci",-1,1),new z("endi",-1,1),new z("erei",-1,1),new z("irei",-1,1),new z("assi",-1,1),new z("ati",-1,1),new z("iti",-1,1),new z("eresti",-1,1),new z("iresti",-1,1),new z("uti",-1,1),new z("avi",-1,1),new z("evi",-1,1),new z("ivi",-1,1),new z("isco",-1,1),new z("ando",-1,1),new z("endo",-1,1),new z("Yamo",-1,1),new z("iamo",-1,1),new z("avamo",-1,1),new z("evamo",-1,1),new z("ivamo",-1,1),new z("eremo",-1,1),new z("iremo",-1,1),new z("assimo",-1,1),new z("ammo",-1,1),new z("emmo",-1,1),new z("eremmo",54,1),new z("iremmo",54,1),new z("immo",-1,1),new z("ano",-1,1),new z("iscano",58,1),new z("avano",58,1),new z("evano",58,1),new z("ivano",58,1),new z("eranno",-1,1),new z("iranno",-1,1),new z("ono",-1,1),new z("iscono",65,1),new z("arono",65,1),new z("erono",65,1),new z("irono",65,1),new z("erebbero",-1,1),new z("irebbero",-1,1),new z("assero",-1,1),new z("essero",-1,1),new z("issero",-1,1),new z("ato",-1,1),new z("ito",-1,1),new z("uto",-1,1),new z("avo",-1,1),new z("evo",-1,1),new z("ivo",-1,1),new z("ar",-1,1),new z("ir",-1,1),new z("erà",-1,1),new z("irà",-1,1),new z("erò",-1,1),new z("irò",-1,1)],m=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,128,128,8,2,1],f=[17,65,0,0,0,0,0,0,0,0,0,0,0,0,0,128,128,8,2],v=[17],b=new P;function d(e,r,n){return!(!b.eq_s(1,e)||(b.ket=b.cursor,!b.in_grouping(m,97,249)))&&(b.slice_from(r),b.cursor=n,!0)}function _(e){if(b.cursor=e,!b.in_grouping(m,97,249))return!1;for(;!b.out_grouping(m,97,249);){if(b.cursor>=b.limit)return!1;b.cursor++}return!0}function g(){var e,r=b.cursor;if(!function(){if(b.in_grouping(m,97,249)){var e=b.cursor;if(b.out_grouping(m,97,249)){for(;!b.in_grouping(m,97,249);){if(b.cursor>=b.limit)return _(e);b.cursor++}return!0}return _(e)}return!1}()){if(b.cursor=r,!b.out_grouping(m,97,249))return;if(e=b.cursor,b.out_grouping(m,97,249)){for(;!b.in_grouping(m,97,249);){if(b.cursor>=b.limit)return b.cursor=e,void(b.in_grouping(m,97,249)&&b.cursor=b.limit)return;b.cursor++}s=b.cursor}function p(){for(;!b.in_grouping(m,97,249);){if(b.cursor>=b.limit)return!1;b.cursor++}for(;!b.out_grouping(m,97,249);){if(b.cursor>=b.limit)return!1;b.cursor++}return!0}function k(){return s<=b.cursor}function h(){return o<=b.cursor}function q(){var e;if(b.ket=b.cursor,!(e=b.find_among_b(i,51)))return!1;switch(b.bra=b.cursor,e){case 1:if(!h())return!1;b.slice_del();break;case 2:if(!h())return!1;b.slice_del(),b.ket=b.cursor,b.eq_s_b(2,"ic")&&(b.bra=b.cursor,h()&&b.slice_del());break;case 3:if(!h())return!1;b.slice_from("log");break;case 4:if(!h())return!1;b.slice_from("u");break;case 5:if(!h())return!1;b.slice_from("ente");break;case 6:if(!k())return!1;b.slice_del();break;case 7:if(!(t<=b.cursor))return!1;b.slice_del(),b.ket=b.cursor,(e=b.find_among_b(r,4))&&(b.bra=b.cursor,h()&&(b.slice_del(),1==e&&(b.ket=b.cursor,b.eq_s_b(2,"at")&&(b.bra=b.cursor,h()&&b.slice_del()))));break;case 8:if(!h())return!1;b.slice_del(),b.ket=b.cursor,(e=b.find_among_b(n,3))&&(b.bra=b.cursor,1==e&&h()&&b.slice_del());break;case 9:if(!h())return!1;b.slice_del(),b.ket=b.cursor,b.eq_s_b(2,"at")&&(b.bra=b.cursor,h()&&(b.slice_del(),b.ket=b.cursor,b.eq_s_b(2,"ic")&&(b.bra=b.cursor,h()&&b.slice_del())))}return!0}function C(){var e;e=b.limit-b.cursor,b.ket=b.cursor,b.in_grouping_b(f,97,242)&&(b.bra=b.cursor,k()&&(b.slice_del(),b.ket=b.cursor,b.eq_s_b(1,"i")&&(b.bra=b.cursor,k())))?b.slice_del():b.cursor=b.limit-e,b.ket=b.cursor,b.eq_s_b(1,"h")&&(b.bra=b.cursor,b.in_grouping_b(v,99,103)&&k()&&b.slice_del())}this.setCurrent=function(e){b.setCurrent(e)},this.getCurrent=function(){return b.getCurrent()},this.stem=function(){var e,r,n,i=b.cursor;return function(){for(var e,r,n,i,o=b.cursor;;){if(b.bra=b.cursor,e=b.find_among(a,7))switch(b.ket=b.cursor,e){case 1:b.slice_from("à");continue;case 2:b.slice_from("è");continue;case 3:b.slice_from("ì");continue;case 4:b.slice_from("ò");continue;case 5:b.slice_from("ù");continue;case 6:b.slice_from("qU");continue;case 7:if(b.cursor>=b.limit)break;b.cursor++;continue}break}for(b.cursor=o;;)for(r=b.cursor;;){if(n=b.cursor,b.in_grouping(m,97,249)){if(b.bra=b.cursor,i=b.cursor,d("u","U",n))break;if(b.cursor=i,d("i","I",n))break}if(b.cursor=n,b.cursor>=b.limit)return b.cursor=r;b.cursor++}}(),b.cursor=i,e=b.cursor,s=b.limit,o=t=s,g(),b.cursor=e,p()&&(t=b.cursor,p()&&(o=b.cursor)),b.limit_backward=i,b.cursor=b.limit,function(){var e;if(b.ket=b.cursor,b.find_among_b(c,37)&&(b.bra=b.cursor,(e=b.find_among_b(w,5))&&k()))switch(e){case 1:b.slice_del();break;case 2:b.slice_from("e")}}(),b.cursor=b.limit,q()||(b.cursor=b.limit,b.cursor>=s&&(n=b.limit_backward,b.limit_backward=s,b.ket=b.cursor,(r=b.find_among_b(l,87))&&(b.bra=b.cursor,1==r&&b.slice_del()),b.limit_backward=n)),b.cursor=b.limit,C(),b.cursor=b.limit_backward,function(){for(var e;b.bra=b.cursor,e=b.find_among(u,3);)switch(b.ket=b.cursor,e){case 1:b.slice_from("i");break;case 2:b.slice_from("u");break;case 3:if(b.cursor>=b.limit)return;b.cursor++}}(),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return r.setCurrent(e),r.stem(),r.getCurrent()}):(r.setCurrent(e),r.stem(),r.getCurrent())}),e.Pipeline.registerFunction(e.it.stemmer,"stemmer-it"),e.it.stopWordFilter=e.generateStopWordFilter("a abbia abbiamo abbiano abbiate ad agl agli ai al all alla alle allo anche avemmo avendo avesse avessero avessi avessimo aveste avesti avete aveva avevamo avevano avevate avevi avevo avrai avranno avrebbe avrebbero avrei avremmo avremo avreste avresti avrete avrà avrò avuta avute avuti avuto c che chi ci coi col come con contro cui da dagl dagli dai dal dall dalla dalle dallo degl degli dei del dell della delle dello di dov dove e ebbe ebbero ebbi ed era erano eravamo eravate eri ero essendo faccia facciamo facciano facciate faccio facemmo facendo facesse facessero facessi facessimo faceste facesti faceva facevamo facevano facevate facevi facevo fai fanno farai faranno farebbe farebbero farei faremmo faremo fareste faresti farete farà farò fece fecero feci fosse fossero fossi fossimo foste fosti fu fui fummo furono gli ha hai hanno ho i il in io l la le lei li lo loro lui ma mi mia mie miei mio ne negl negli nei nel nell nella nelle nello noi non nostra nostre nostri nostro o per perché più quale quanta quante quanti quanto quella quelle quelli quello questa queste questi questo sarai saranno sarebbe sarebbero sarei saremmo saremo sareste saresti sarete sarà sarò se sei si sia siamo siano siate siete sono sta stai stando stanno starai staranno starebbe starebbero starei staremmo staremo stareste staresti starete starà starò stava stavamo stavano stavate stavi stavo stemmo stesse stessero stessi stessimo steste stesti stette stettero stetti stia stiamo stiano stiate sto su sua sue sugl sugli sui sul sull sulla sulle sullo suo suoi ti tra tu tua tue tuo tuoi tutti tutto un una uno vi voi vostra vostre vostri vostro è".split(" ")),e.Pipeline.registerFunction(e.it.stopWordFilter,"stopWordFilter-it")}}); \ No newline at end of file diff --git a/_static/javascripts/lunr/lunr.ja.js b/_static/javascripts/lunr/lunr.ja.js new file mode 100644 index 0000000000..69f620250d --- /dev/null +++ b/_static/javascripts/lunr/lunr.ja.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(m){if(void 0===m)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===m.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var l="2"==m.version[0];m.ja=function(){this.pipeline.reset(),this.pipeline.add(m.ja.trimmer,m.ja.stopWordFilter,m.ja.stemmer),l?this.tokenizer=m.ja.tokenizer:(m.tokenizer&&(m.tokenizer=m.ja.tokenizer),this.tokenizerFn&&(this.tokenizerFn=m.ja.tokenizer))};var j=new m.TinySegmenter;m.ja.tokenizer=function(e){var r,t,i,n,o,s,p,a,u;if(!arguments.length||null==e||null==e)return[];if(Array.isArray(e))return e.map(function(e){return l?new m.Token(e.toLowerCase()):e.toLowerCase()});for(r=(t=e.toString().toLowerCase().replace(/^\s+/,"")).length-1;0<=r;r--)if(/\S/.test(t.charAt(r))){t=t.substring(0,r+1);break}for(o=[],i=t.length,p=a=0;a<=i;a++)if(s=a-p,t.charAt(a).match(/\s/)||a==i){if(0=_.limit||(_.cursor++,!1)}function w(){for(;!_.in_grouping(m,97,232);){if(_.cursor>=_.limit)return!0;_.cursor++}for(;!_.out_grouping(m,97,232);){if(_.cursor>=_.limit)return!0;_.cursor++}return!1}function b(){return i<=_.cursor}function p(){return e<=_.cursor}function g(){var r=_.limit-_.cursor;_.find_among_b(t,3)&&(_.cursor=_.limit-r,_.ket=_.cursor,_.cursor>_.limit_backward&&(_.cursor--,_.bra=_.cursor,_.slice_del()))}function h(){var r;u=!1,_.ket=_.cursor,_.eq_s_b(1,"e")&&(_.bra=_.cursor,b()&&(r=_.limit-_.cursor,_.out_grouping_b(m,97,232)&&(_.cursor=_.limit-r,_.slice_del(),u=!0,g())))}function k(){var r;b()&&(r=_.limit-_.cursor,_.out_grouping_b(m,97,232)&&(_.cursor=_.limit-r,_.eq_s_b(3,"gem")||(_.cursor=_.limit-r,_.slice_del(),g())))}this.setCurrent=function(r){_.setCurrent(r)},this.getCurrent=function(){return _.getCurrent()},this.stem=function(){var r=_.cursor;return function(){for(var r,e,i,n=_.cursor;;){if(_.bra=_.cursor,r=_.find_among(o,11))switch(_.ket=_.cursor,r){case 1:_.slice_from("a");continue;case 2:_.slice_from("e");continue;case 3:_.slice_from("i");continue;case 4:_.slice_from("o");continue;case 5:_.slice_from("u");continue;case 6:if(_.cursor>=_.limit)break;_.cursor++;continue}break}for(_.cursor=n,_.bra=n,_.eq_s(1,"y")?(_.ket=_.cursor,_.slice_from("Y")):_.cursor=n;;)if(e=_.cursor,_.in_grouping(m,97,232)){if(i=_.cursor,_.bra=i,_.eq_s(1,"i"))_.ket=_.cursor,_.in_grouping(m,97,232)&&(_.slice_from("I"),_.cursor=e);else if(_.cursor=i,_.eq_s(1,"y"))_.ket=_.cursor,_.slice_from("Y"),_.cursor=e;else if(s(e))break}else if(s(e))break}(),_.cursor=r,i=_.limit,e=i,w()||((i=_.cursor)<3&&(i=3),w()||(e=_.cursor)),_.limit_backward=r,_.cursor=_.limit,function(){var r,e,i,n,o,t,s=_.limit-_.cursor;if(_.ket=_.cursor,r=_.find_among_b(c,5))switch(_.bra=_.cursor,r){case 1:b()&&_.slice_from("heid");break;case 2:k();break;case 3:b()&&_.out_grouping_b(f,97,232)&&_.slice_del()}if(_.cursor=_.limit-s,h(),_.cursor=_.limit-s,_.ket=_.cursor,_.eq_s_b(4,"heid")&&(_.bra=_.cursor,p()&&(e=_.limit-_.cursor,_.eq_s_b(1,"c")||(_.cursor=_.limit-e,_.slice_del(),_.ket=_.cursor,_.eq_s_b(2,"en")&&(_.bra=_.cursor,k())))),_.cursor=_.limit-s,_.ket=_.cursor,r=_.find_among_b(a,6))switch(_.bra=_.cursor,r){case 1:if(p()){if(_.slice_del(),i=_.limit-_.cursor,_.ket=_.cursor,_.eq_s_b(2,"ig")&&(_.bra=_.cursor,p()&&(n=_.limit-_.cursor,!_.eq_s_b(1,"e")))){_.cursor=_.limit-n,_.slice_del();break}_.cursor=_.limit-i,g()}break;case 2:p()&&(o=_.limit-_.cursor,_.eq_s_b(1,"e")||(_.cursor=_.limit-o,_.slice_del()));break;case 3:p()&&(_.slice_del(),h());break;case 4:p()&&_.slice_del();break;case 5:p()&&u&&_.slice_del()}_.cursor=_.limit-s,_.out_grouping_b(d,73,232)&&(t=_.limit-_.cursor,_.find_among_b(l,4)&&_.out_grouping_b(m,97,232)&&(_.cursor=_.limit-t,_.ket=_.cursor,_.cursor>_.limit_backward&&(_.cursor--,_.bra=_.cursor,_.slice_del())))}(),_.cursor=_.limit_backward,function(){for(var r;;)if(_.bra=_.cursor,r=_.find_among(n,3))switch(_.ket=_.cursor,r){case 1:_.slice_from("y");break;case 2:_.slice_from("i");break;case 3:if(_.cursor>=_.limit)return;_.cursor++}}(),!0}},function(r){return"function"==typeof r.update?r.update(function(r){return e.setCurrent(r),e.stem(),e.getCurrent()}):(e.setCurrent(r),e.stem(),e.getCurrent())}),r.Pipeline.registerFunction(r.nl.stemmer,"stemmer-nl"),r.nl.stopWordFilter=r.generateStopWordFilter(" aan al alles als altijd andere ben bij daar dan dat de der deze die dit doch doen door dus een eens en er ge geen geweest haar had heb hebben heeft hem het hier hij hoe hun iemand iets ik in is ja je kan kon kunnen maar me meer men met mij mijn moet na naar niet niets nog nu of om omdat onder ons ook op over reeds te tegen toch toen tot u uit uw van veel voor want waren was wat werd wezen wie wil worden wordt zal ze zelf zich zij zijn zo zonder zou".split(" ")),r.Pipeline.registerFunction(r.nl.stopWordFilter,"stopWordFilter-nl")}}); \ No newline at end of file diff --git a/_static/javascripts/lunr/lunr.no.js b/_static/javascripts/lunr/lunr.no.js new file mode 100644 index 0000000000..3d156b9c19 --- /dev/null +++ b/_static/javascripts/lunr/lunr.no.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r,n,i;e.no=function(){this.pipeline.reset(),this.pipeline.add(e.no.trimmer,e.no.stopWordFilter,e.no.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.no.stemmer))},e.no.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.no.trimmer=e.trimmerSupport.generateTrimmer(e.no.wordCharacters),e.Pipeline.registerFunction(e.no.trimmer,"trimmer-no"),e.no.stemmer=(r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){var o,s,a=[new r("a",-1,1),new r("e",-1,1),new r("ede",1,1),new r("ande",1,1),new r("ende",1,1),new r("ane",1,1),new r("ene",1,1),new r("hetene",6,1),new r("erte",1,3),new r("en",-1,1),new r("heten",9,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",12,1),new r("s",-1,2),new r("as",14,1),new r("es",14,1),new r("edes",16,1),new r("endes",16,1),new r("enes",16,1),new r("hetenes",19,1),new r("ens",14,1),new r("hetens",21,1),new r("ers",14,1),new r("ets",14,1),new r("et",-1,1),new r("het",25,1),new r("ert",-1,3),new r("ast",-1,1)],m=[new r("dt",-1,-1),new r("vt",-1,-1)],l=[new r("leg",-1,1),new r("eleg",0,1),new r("ig",-1,1),new r("eig",2,1),new r("lig",2,1),new r("elig",4,1),new r("els",-1,1),new r("lov",-1,1),new r("elov",7,1),new r("slov",7,1),new r("hetslov",9,1)],u=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],d=[119,125,149,1],c=new n;this.setCurrent=function(e){c.setCurrent(e)},this.getCurrent=function(){return c.getCurrent()},this.stem=function(){var e,r,n,i,t=c.cursor;return function(){var e,r=c.cursor+3;if(s=c.limit,0<=r||r<=c.limit){for(o=r;;){if(e=c.cursor,c.in_grouping(u,97,248)){c.cursor=e;break}if(e>=c.limit)return;c.cursor=e+1}for(;!c.out_grouping(u,97,248);){if(c.cursor>=c.limit)return;c.cursor++}(s=c.cursor)=s&&(r=c.limit_backward,c.limit_backward=s,c.ket=c.cursor,e=c.find_among_b(a,29),c.limit_backward=r,e))switch(c.bra=c.cursor,e){case 1:c.slice_del();break;case 2:n=c.limit-c.cursor,c.in_grouping_b(d,98,122)?c.slice_del():(c.cursor=c.limit-n,c.eq_s_b(1,"k")&&c.out_grouping_b(u,97,248)&&c.slice_del());break;case 3:c.slice_from("er")}}(),c.cursor=c.limit,r=c.limit-c.cursor,c.cursor>=s&&(e=c.limit_backward,c.limit_backward=s,c.ket=c.cursor,c.find_among_b(m,2)?(c.bra=c.cursor,c.limit_backward=e,c.cursor=c.limit-r,c.cursor>c.limit_backward&&(c.cursor--,c.bra=c.cursor,c.slice_del())):c.limit_backward=e),c.cursor=c.limit,c.cursor>=s&&(i=c.limit_backward,c.limit_backward=s,c.ket=c.cursor,(n=c.find_among_b(l,11))?(c.bra=c.cursor,c.limit_backward=i,1==n&&c.slice_del()):c.limit_backward=i),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}),e.Pipeline.registerFunction(e.no.stemmer,"stemmer-no"),e.no.stopWordFilter=e.generateStopWordFilter("alle at av bare begge ble blei bli blir blitt både båe da de deg dei deim deira deires dem den denne der dere deres det dette di din disse ditt du dykk dykkar då eg ein eit eitt eller elles en enn er et ett etter for fordi fra før ha hadde han hans har hennar henne hennes her hjå ho hoe honom hoss hossen hun hva hvem hver hvilke hvilken hvis hvor hvordan hvorfor i ikke ikkje ikkje ingen ingi inkje inn inni ja jeg kan kom korleis korso kun kunne kva kvar kvarhelst kven kvi kvifor man mange me med medan meg meget mellom men mi min mine mitt mot mykje ned no noe noen noka noko nokon nokor nokre nå når og også om opp oss over på samme seg selv si si sia sidan siden sin sine sitt sjøl skal skulle slik so som som somme somt så sånn til um upp ut uten var vart varte ved vere verte vi vil ville vore vors vort vår være være vært å".split(" ")),e.Pipeline.registerFunction(e.no.stopWordFilter,"stopWordFilter-no")}}); \ No newline at end of file diff --git a/_static/javascripts/lunr/lunr.pt.js b/_static/javascripts/lunr/lunr.pt.js new file mode 100644 index 0000000000..f50fc9fa6d --- /dev/null +++ b/_static/javascripts/lunr/lunr.pt.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var j,C,r;e.pt=function(){this.pipeline.reset(),this.pipeline.add(e.pt.trimmer,e.pt.stopWordFilter,e.pt.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.pt.stemmer))},e.pt.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.pt.trimmer=e.trimmerSupport.generateTrimmer(e.pt.wordCharacters),e.Pipeline.registerFunction(e.pt.trimmer,"trimmer-pt"),e.pt.stemmer=(j=e.stemmerSupport.Among,C=e.stemmerSupport.SnowballProgram,r=new function(){var s,n,i,o=[new j("",-1,3),new j("ã",0,1),new j("õ",0,2)],a=[new j("",-1,3),new j("a~",0,1),new j("o~",0,2)],r=[new j("ic",-1,-1),new j("ad",-1,-1),new j("os",-1,-1),new j("iv",-1,1)],t=[new j("ante",-1,1),new j("avel",-1,1),new j("ível",-1,1)],u=[new j("ic",-1,1),new j("abil",-1,1),new j("iv",-1,1)],w=[new j("ica",-1,1),new j("ância",-1,1),new j("ência",-1,4),new j("ira",-1,9),new j("adora",-1,1),new j("osa",-1,1),new j("ista",-1,1),new j("iva",-1,8),new j("eza",-1,1),new j("logía",-1,2),new j("idade",-1,7),new j("ante",-1,1),new j("mente",-1,6),new j("amente",12,5),new j("ável",-1,1),new j("ível",-1,1),new j("ución",-1,3),new j("ico",-1,1),new j("ismo",-1,1),new j("oso",-1,1),new j("amento",-1,1),new j("imento",-1,1),new j("ivo",-1,8),new j("aça~o",-1,1),new j("ador",-1,1),new j("icas",-1,1),new j("ências",-1,4),new j("iras",-1,9),new j("adoras",-1,1),new j("osas",-1,1),new j("istas",-1,1),new j("ivas",-1,8),new j("ezas",-1,1),new j("logías",-1,2),new j("idades",-1,7),new j("uciones",-1,3),new j("adores",-1,1),new j("antes",-1,1),new j("aço~es",-1,1),new j("icos",-1,1),new j("ismos",-1,1),new j("osos",-1,1),new j("amentos",-1,1),new j("imentos",-1,1),new j("ivos",-1,8)],m=[new j("ada",-1,1),new j("ida",-1,1),new j("ia",-1,1),new j("aria",2,1),new j("eria",2,1),new j("iria",2,1),new j("ara",-1,1),new j("era",-1,1),new j("ira",-1,1),new j("ava",-1,1),new j("asse",-1,1),new j("esse",-1,1),new j("isse",-1,1),new j("aste",-1,1),new j("este",-1,1),new j("iste",-1,1),new j("ei",-1,1),new j("arei",16,1),new j("erei",16,1),new j("irei",16,1),new j("am",-1,1),new j("iam",20,1),new j("ariam",21,1),new j("eriam",21,1),new j("iriam",21,1),new j("aram",20,1),new j("eram",20,1),new j("iram",20,1),new j("avam",20,1),new j("em",-1,1),new j("arem",29,1),new j("erem",29,1),new j("irem",29,1),new j("assem",29,1),new j("essem",29,1),new j("issem",29,1),new j("ado",-1,1),new j("ido",-1,1),new j("ando",-1,1),new j("endo",-1,1),new j("indo",-1,1),new j("ara~o",-1,1),new j("era~o",-1,1),new j("ira~o",-1,1),new j("ar",-1,1),new j("er",-1,1),new j("ir",-1,1),new j("as",-1,1),new j("adas",47,1),new j("idas",47,1),new j("ias",47,1),new j("arias",50,1),new j("erias",50,1),new j("irias",50,1),new j("aras",47,1),new j("eras",47,1),new j("iras",47,1),new j("avas",47,1),new j("es",-1,1),new j("ardes",58,1),new j("erdes",58,1),new j("irdes",58,1),new j("ares",58,1),new j("eres",58,1),new j("ires",58,1),new j("asses",58,1),new j("esses",58,1),new j("isses",58,1),new j("astes",58,1),new j("estes",58,1),new j("istes",58,1),new j("is",-1,1),new j("ais",71,1),new j("eis",71,1),new j("areis",73,1),new j("ereis",73,1),new j("ireis",73,1),new j("áreis",73,1),new j("éreis",73,1),new j("íreis",73,1),new j("ásseis",73,1),new j("ésseis",73,1),new j("ísseis",73,1),new j("áveis",73,1),new j("íeis",73,1),new j("aríeis",84,1),new j("eríeis",84,1),new j("iríeis",84,1),new j("ados",-1,1),new j("idos",-1,1),new j("amos",-1,1),new j("áramos",90,1),new j("éramos",90,1),new j("íramos",90,1),new j("ávamos",90,1),new j("íamos",90,1),new j("aríamos",95,1),new j("eríamos",95,1),new j("iríamos",95,1),new j("emos",-1,1),new j("aremos",99,1),new j("eremos",99,1),new j("iremos",99,1),new j("ássemos",99,1),new j("êssemos",99,1),new j("íssemos",99,1),new j("imos",-1,1),new j("armos",-1,1),new j("ermos",-1,1),new j("irmos",-1,1),new j("ámos",-1,1),new j("arás",-1,1),new j("erás",-1,1),new j("irás",-1,1),new j("eu",-1,1),new j("iu",-1,1),new j("ou",-1,1),new j("ará",-1,1),new j("erá",-1,1),new j("irá",-1,1)],c=[new j("a",-1,1),new j("i",-1,1),new j("o",-1,1),new j("os",-1,1),new j("á",-1,1),new j("í",-1,1),new j("ó",-1,1)],l=[new j("e",-1,1),new j("ç",-1,2),new j("é",-1,1),new j("ê",-1,1)],f=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,3,19,12,2],d=new C;function v(){if(d.out_grouping(f,97,250)){for(;!d.in_grouping(f,97,250);){if(d.cursor>=d.limit)return!0;d.cursor++}return!1}return!0}function p(){var e,r,s=d.cursor;if(d.in_grouping(f,97,250))if(e=d.cursor,v()){if(d.cursor=e,function(){if(d.in_grouping(f,97,250))for(;!d.out_grouping(f,97,250);){if(d.cursor>=d.limit)return!1;d.cursor++}return i=d.cursor,!0}())return}else i=d.cursor;if(d.cursor=s,d.out_grouping(f,97,250)){if(r=d.cursor,v()){if(d.cursor=r,!d.in_grouping(f,97,250)||d.cursor>=d.limit)return;d.cursor++}i=d.cursor}}function _(){for(;!d.in_grouping(f,97,250);){if(d.cursor>=d.limit)return!1;d.cursor++}for(;!d.out_grouping(f,97,250);){if(d.cursor>=d.limit)return!1;d.cursor++}return!0}function h(){return i<=d.cursor}function b(){return s<=d.cursor}function g(){var e;if(d.ket=d.cursor,!(e=d.find_among_b(w,45)))return!1;switch(d.bra=d.cursor,e){case 1:if(!b())return!1;d.slice_del();break;case 2:if(!b())return!1;d.slice_from("log");break;case 3:if(!b())return!1;d.slice_from("u");break;case 4:if(!b())return!1;d.slice_from("ente");break;case 5:if(!(n<=d.cursor))return!1;d.slice_del(),d.ket=d.cursor,(e=d.find_among_b(r,4))&&(d.bra=d.cursor,b()&&(d.slice_del(),1==e&&(d.ket=d.cursor,d.eq_s_b(2,"at")&&(d.bra=d.cursor,b()&&d.slice_del()))));break;case 6:if(!b())return!1;d.slice_del(),d.ket=d.cursor,(e=d.find_among_b(t,3))&&(d.bra=d.cursor,1==e&&b()&&d.slice_del());break;case 7:if(!b())return!1;d.slice_del(),d.ket=d.cursor,(e=d.find_among_b(u,3))&&(d.bra=d.cursor,1==e&&b()&&d.slice_del());break;case 8:if(!b())return!1;d.slice_del(),d.ket=d.cursor,d.eq_s_b(2,"at")&&(d.bra=d.cursor,b()&&d.slice_del());break;case 9:if(!h()||!d.eq_s_b(1,"e"))return!1;d.slice_from("ir")}return!0}function k(e,r){if(d.eq_s_b(1,e)){d.bra=d.cursor;var s=d.limit-d.cursor;if(d.eq_s_b(1,r))return d.cursor=d.limit-s,h()&&d.slice_del(),!1}return!0}function q(){if(!g()&&(d.cursor=d.limit,!function(){var e,r;if(d.cursor>=i){if(r=d.limit_backward,d.limit_backward=i,d.ket=d.cursor,e=d.find_among_b(m,120))return d.bra=d.cursor,1==e&&d.slice_del(),d.limit_backward=r,!0;d.limit_backward=r}return!1}()))return d.cursor=d.limit,d.ket=d.cursor,void((e=d.find_among_b(c,7))&&(d.bra=d.cursor,1==e&&h()&&d.slice_del()));var e;d.cursor=d.limit,d.ket=d.cursor,d.eq_s_b(1,"i")&&(d.bra=d.cursor,d.eq_s_b(1,"c")&&(d.cursor=d.limit,h()&&d.slice_del()))}this.setCurrent=function(e){d.setCurrent(e)},this.getCurrent=function(){return d.getCurrent()},this.stem=function(){var e,r=d.cursor;return function(){for(var e;;){if(d.bra=d.cursor,e=d.find_among(o,3))switch(d.ket=d.cursor,e){case 1:d.slice_from("a~");continue;case 2:d.slice_from("o~");continue;case 3:if(d.cursor>=d.limit)break;d.cursor++;continue}break}}(),d.cursor=r,e=d.cursor,i=d.limit,s=n=i,p(),d.cursor=e,_()&&(n=d.cursor,_()&&(s=d.cursor)),d.limit_backward=r,d.cursor=d.limit,q(),d.cursor=d.limit,function(){var e;if(d.ket=d.cursor,e=d.find_among_b(l,4))switch(d.bra=d.cursor,e){case 1:h()&&(d.slice_del(),d.ket=d.cursor,d.limit,d.cursor,k("u","g")&&k("i","c"));break;case 2:d.slice_from("c")}}(),d.cursor=d.limit_backward,function(){for(var e;;){if(d.bra=d.cursor,e=d.find_among(a,3))switch(d.ket=d.cursor,e){case 1:d.slice_from("ã");continue;case 2:d.slice_from("õ");continue;case 3:if(d.cursor>=d.limit)break;d.cursor++;continue}break}}(),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return r.setCurrent(e),r.stem(),r.getCurrent()}):(r.setCurrent(e),r.stem(),r.getCurrent())}),e.Pipeline.registerFunction(e.pt.stemmer,"stemmer-pt"),e.pt.stopWordFilter=e.generateStopWordFilter("a ao aos aquela aquelas aquele aqueles aquilo as até com como da das de dela delas dele deles depois do dos e ela elas ele eles em entre era eram essa essas esse esses esta estamos estas estava estavam este esteja estejam estejamos estes esteve estive estivemos estiver estivera estiveram estiverem estivermos estivesse estivessem estivéramos estivéssemos estou está estávamos estão eu foi fomos for fora foram forem formos fosse fossem fui fôramos fôssemos haja hajam hajamos havemos hei houve houvemos houver houvera houveram houverei houverem houveremos houveria houveriam houvermos houverá houverão houveríamos houvesse houvessem houvéramos houvéssemos há hão isso isto já lhe lhes mais mas me mesmo meu meus minha minhas muito na nas nem no nos nossa nossas nosso nossos num numa não nós o os ou para pela pelas pelo pelos por qual quando que quem se seja sejam sejamos sem serei seremos seria seriam será serão seríamos seu seus somos sou sua suas são só também te tem temos tenha tenham tenhamos tenho terei teremos teria teriam terá terão teríamos teu teus teve tinha tinham tive tivemos tiver tivera tiveram tiverem tivermos tivesse tivessem tivéramos tivéssemos tu tua tuas tém tínhamos um uma você vocês vos à às éramos".split(" ")),e.Pipeline.registerFunction(e.pt.stopWordFilter,"stopWordFilter-pt")}}); \ No newline at end of file diff --git a/_static/javascripts/lunr/lunr.ro.js b/_static/javascripts/lunr/lunr.ro.js new file mode 100644 index 0000000000..b19627e1b3 --- /dev/null +++ b/_static/javascripts/lunr/lunr.ro.js @@ -0,0 +1 @@ +!function(e,i){"function"==typeof define&&define.amd?define(i):"object"==typeof exports?module.exports=i():i()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var h,z,i;e.ro=function(){this.pipeline.reset(),this.pipeline.add(e.ro.trimmer,e.ro.stopWordFilter,e.ro.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.ro.stemmer))},e.ro.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.ro.trimmer=e.trimmerSupport.generateTrimmer(e.ro.wordCharacters),e.Pipeline.registerFunction(e.ro.trimmer,"trimmer-ro"),e.ro.stemmer=(h=e.stemmerSupport.Among,z=e.stemmerSupport.SnowballProgram,i=new function(){var r,n,t,a,o=[new h("",-1,3),new h("I",0,1),new h("U",0,2)],s=[new h("ea",-1,3),new h("aţia",-1,7),new h("aua",-1,2),new h("iua",-1,4),new h("aţie",-1,7),new h("ele",-1,3),new h("ile",-1,5),new h("iile",6,4),new h("iei",-1,4),new h("atei",-1,6),new h("ii",-1,4),new h("ului",-1,1),new h("ul",-1,1),new h("elor",-1,3),new h("ilor",-1,4),new h("iilor",14,4)],c=[new h("icala",-1,4),new h("iciva",-1,4),new h("ativa",-1,5),new h("itiva",-1,6),new h("icale",-1,4),new h("aţiune",-1,5),new h("iţiune",-1,6),new h("atoare",-1,5),new h("itoare",-1,6),new h("ătoare",-1,5),new h("icitate",-1,4),new h("abilitate",-1,1),new h("ibilitate",-1,2),new h("ivitate",-1,3),new h("icive",-1,4),new h("ative",-1,5),new h("itive",-1,6),new h("icali",-1,4),new h("atori",-1,5),new h("icatori",18,4),new h("itori",-1,6),new h("ători",-1,5),new h("icitati",-1,4),new h("abilitati",-1,1),new h("ivitati",-1,3),new h("icivi",-1,4),new h("ativi",-1,5),new h("itivi",-1,6),new h("icităi",-1,4),new h("abilităi",-1,1),new h("ivităi",-1,3),new h("icităţi",-1,4),new h("abilităţi",-1,1),new h("ivităţi",-1,3),new h("ical",-1,4),new h("ator",-1,5),new h("icator",35,4),new h("itor",-1,6),new h("ător",-1,5),new h("iciv",-1,4),new h("ativ",-1,5),new h("itiv",-1,6),new h("icală",-1,4),new h("icivă",-1,4),new h("ativă",-1,5),new h("itivă",-1,6)],u=[new h("ica",-1,1),new h("abila",-1,1),new h("ibila",-1,1),new h("oasa",-1,1),new h("ata",-1,1),new h("ita",-1,1),new h("anta",-1,1),new h("ista",-1,3),new h("uta",-1,1),new h("iva",-1,1),new h("ic",-1,1),new h("ice",-1,1),new h("abile",-1,1),new h("ibile",-1,1),new h("isme",-1,3),new h("iune",-1,2),new h("oase",-1,1),new h("ate",-1,1),new h("itate",17,1),new h("ite",-1,1),new h("ante",-1,1),new h("iste",-1,3),new h("ute",-1,1),new h("ive",-1,1),new h("ici",-1,1),new h("abili",-1,1),new h("ibili",-1,1),new h("iuni",-1,2),new h("atori",-1,1),new h("osi",-1,1),new h("ati",-1,1),new h("itati",30,1),new h("iti",-1,1),new h("anti",-1,1),new h("isti",-1,3),new h("uti",-1,1),new h("işti",-1,3),new h("ivi",-1,1),new h("ităi",-1,1),new h("oşi",-1,1),new h("ităţi",-1,1),new h("abil",-1,1),new h("ibil",-1,1),new h("ism",-1,3),new h("ator",-1,1),new h("os",-1,1),new h("at",-1,1),new h("it",-1,1),new h("ant",-1,1),new h("ist",-1,3),new h("ut",-1,1),new h("iv",-1,1),new h("ică",-1,1),new h("abilă",-1,1),new h("ibilă",-1,1),new h("oasă",-1,1),new h("ată",-1,1),new h("ită",-1,1),new h("antă",-1,1),new h("istă",-1,3),new h("ută",-1,1),new h("ivă",-1,1)],w=[new h("ea",-1,1),new h("ia",-1,1),new h("esc",-1,1),new h("ăsc",-1,1),new h("ind",-1,1),new h("ând",-1,1),new h("are",-1,1),new h("ere",-1,1),new h("ire",-1,1),new h("âre",-1,1),new h("se",-1,2),new h("ase",10,1),new h("sese",10,2),new h("ise",10,1),new h("use",10,1),new h("âse",10,1),new h("eşte",-1,1),new h("ăşte",-1,1),new h("eze",-1,1),new h("ai",-1,1),new h("eai",19,1),new h("iai",19,1),new h("sei",-1,2),new h("eşti",-1,1),new h("ăşti",-1,1),new h("ui",-1,1),new h("ezi",-1,1),new h("âi",-1,1),new h("aşi",-1,1),new h("seşi",-1,2),new h("aseşi",29,1),new h("seseşi",29,2),new h("iseşi",29,1),new h("useşi",29,1),new h("âseşi",29,1),new h("işi",-1,1),new h("uşi",-1,1),new h("âşi",-1,1),new h("aţi",-1,2),new h("eaţi",38,1),new h("iaţi",38,1),new h("eţi",-1,2),new h("iţi",-1,2),new h("âţi",-1,2),new h("arăţi",-1,1),new h("serăţi",-1,2),new h("aserăţi",45,1),new h("seserăţi",45,2),new h("iserăţi",45,1),new h("userăţi",45,1),new h("âserăţi",45,1),new h("irăţi",-1,1),new h("urăţi",-1,1),new h("ârăţi",-1,1),new h("am",-1,1),new h("eam",54,1),new h("iam",54,1),new h("em",-1,2),new h("asem",57,1),new h("sesem",57,2),new h("isem",57,1),new h("usem",57,1),new h("âsem",57,1),new h("im",-1,2),new h("âm",-1,2),new h("ăm",-1,2),new h("arăm",65,1),new h("serăm",65,2),new h("aserăm",67,1),new h("seserăm",67,2),new h("iserăm",67,1),new h("userăm",67,1),new h("âserăm",67,1),new h("irăm",65,1),new h("urăm",65,1),new h("ârăm",65,1),new h("au",-1,1),new h("eau",76,1),new h("iau",76,1),new h("indu",-1,1),new h("ându",-1,1),new h("ez",-1,1),new h("ească",-1,1),new h("ară",-1,1),new h("seră",-1,2),new h("aseră",84,1),new h("seseră",84,2),new h("iseră",84,1),new h("useră",84,1),new h("âseră",84,1),new h("iră",-1,1),new h("ură",-1,1),new h("âră",-1,1),new h("ează",-1,1)],i=[new h("a",-1,1),new h("e",-1,1),new h("ie",1,1),new h("i",-1,1),new h("ă",-1,1)],m=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,2,32,0,0,4],l=new z;function f(e,i){l.eq_s(1,e)&&(l.ket=l.cursor,l.in_grouping(m,97,259)&&l.slice_from(i))}function p(){if(l.out_grouping(m,97,259)){for(;!l.in_grouping(m,97,259);){if(l.cursor>=l.limit)return!0;l.cursor++}return!1}return!0}function d(){var e,i,r=l.cursor;if(l.in_grouping(m,97,259)){if(e=l.cursor,!p())return void(a=l.cursor);if(l.cursor=e,!function(){if(l.in_grouping(m,97,259))for(;!l.out_grouping(m,97,259);){if(l.cursor>=l.limit)return!0;l.cursor++}return!1}())return void(a=l.cursor)}l.cursor=r,l.out_grouping(m,97,259)&&(i=l.cursor,p()&&(l.cursor=i,l.in_grouping(m,97,259)&&l.cursor=l.limit)return!1;l.cursor++}for(;!l.out_grouping(m,97,259);){if(l.cursor>=l.limit)return!1;l.cursor++}return!0}function v(){return t<=l.cursor}function _(){var e,i=l.limit-l.cursor;if(l.ket=l.cursor,(e=l.find_among_b(c,46))&&(l.bra=l.cursor,v())){switch(e){case 1:l.slice_from("abil");break;case 2:l.slice_from("ibil");break;case 3:l.slice_from("iv");break;case 4:l.slice_from("ic");break;case 5:l.slice_from("at");break;case 6:l.slice_from("it")}return r=!0,l.cursor=l.limit-i,!0}return!1}function g(){var e,i;for(r=!1;;)if(i=l.limit-l.cursor,!_()){l.cursor=l.limit-i;break}if(l.ket=l.cursor,(e=l.find_among_b(u,62))&&(l.bra=l.cursor,n<=l.cursor)){switch(e){case 1:l.slice_del();break;case 2:l.eq_s_b(1,"ţ")&&(l.bra=l.cursor,l.slice_from("t"));break;case 3:l.slice_from("ist")}r=!0}}function k(){var e;l.ket=l.cursor,(e=l.find_among_b(i,5))&&(l.bra=l.cursor,a<=l.cursor&&1==e&&l.slice_del())}this.setCurrent=function(e){l.setCurrent(e)},this.getCurrent=function(){return l.getCurrent()},this.stem=function(){var e,i=l.cursor;return function(){for(var e,i;e=l.cursor,l.in_grouping(m,97,259)&&(i=l.cursor,l.bra=i,f("u","U"),l.cursor=i,f("i","I")),l.cursor=e,!(l.cursor>=l.limit);)l.cursor++}(),l.cursor=i,e=l.cursor,a=l.limit,n=t=a,d(),l.cursor=e,b()&&(t=l.cursor,b()&&(n=l.cursor)),l.limit_backward=i,l.cursor=l.limit,function(){var e,i;if(l.ket=l.cursor,(e=l.find_among_b(s,16))&&(l.bra=l.cursor,v()))switch(e){case 1:l.slice_del();break;case 2:l.slice_from("a");break;case 3:l.slice_from("e");break;case 4:l.slice_from("i");break;case 5:i=l.limit-l.cursor,l.eq_s_b(2,"ab")||(l.cursor=l.limit-i,l.slice_from("i"));break;case 6:l.slice_from("at");break;case 7:l.slice_from("aţi")}}(),l.cursor=l.limit,g(),l.cursor=l.limit,r||(l.cursor=l.limit,function(){var e,i,r;if(l.cursor>=a){if(i=l.limit_backward,l.limit_backward=a,l.ket=l.cursor,e=l.find_among_b(w,94))switch(l.bra=l.cursor,e){case 1:if(r=l.limit-l.cursor,!l.out_grouping_b(m,97,259)&&(l.cursor=l.limit-r,!l.eq_s_b(1,"u")))break;case 2:l.slice_del()}l.limit_backward=i}}(),l.cursor=l.limit),k(),l.cursor=l.limit_backward,function(){for(var e;;){if(l.bra=l.cursor,e=l.find_among(o,3))switch(l.ket=l.cursor,e){case 1:l.slice_from("i");continue;case 2:l.slice_from("u");continue;case 3:if(l.cursor>=l.limit)break;l.cursor++;continue}break}}(),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}),e.Pipeline.registerFunction(e.ro.stemmer,"stemmer-ro"),e.ro.stopWordFilter=e.generateStopWordFilter("acea aceasta această aceea acei aceia acel acela acele acelea acest acesta aceste acestea aceşti aceştia acolo acord acum ai aia aibă aici al ale alea altceva altcineva am ar are asemenea asta astea astăzi asupra au avea avem aveţi azi aş aşadar aţi bine bucur bună ca care caut ce cel ceva chiar cinci cine cineva contra cu cum cumva curând curînd când cât câte câtva câţi cînd cît cîte cîtva cîţi că căci cărei căror cărui către da dacă dar datorită dată dau de deci deja deoarece departe deşi din dinaintea dintr- dintre doi doilea două drept după dă ea ei el ele eram este eu eşti face fata fi fie fiecare fii fim fiu fiţi frumos fără graţie halbă iar ieri la le li lor lui lângă lîngă mai mea mei mele mereu meu mi mie mine mult multă mulţi mulţumesc mâine mîine mă ne nevoie nici nicăieri nimeni nimeri nimic nişte noastre noastră noi noroc nostru nouă noştri nu opt ori oricare orice oricine oricum oricând oricât oricînd oricît oriunde patra patru patrulea pe pentru peste pic poate pot prea prima primul prin puţin puţina puţină până pînă rog sa sale sau se spate spre sub sunt suntem sunteţi sută sînt sîntem sînteţi să săi său ta tale te timp tine toate toată tot totuşi toţi trei treia treilea tu tăi tău un una unde undeva unei uneia unele uneori unii unor unora unu unui unuia unul vi voastre voastră voi vostru vouă voştri vreme vreo vreun vă zece zero zi zice îi îl îmi împotriva în înainte înaintea încotro încât încît între întrucât întrucît îţi ăla ălea ăsta ăstea ăştia şapte şase şi ştiu ţi ţie".split(" ")),e.Pipeline.registerFunction(e.ro.stopWordFilter,"stopWordFilter-ro")}}); \ No newline at end of file diff --git a/_static/javascripts/lunr/lunr.ru.js b/_static/javascripts/lunr/lunr.ru.js new file mode 100644 index 0000000000..ac99248044 --- /dev/null +++ b/_static/javascripts/lunr/lunr.ru.js @@ -0,0 +1 @@ +!function(e,n){"function"==typeof define&&define.amd?define(n):"object"==typeof exports?module.exports=n():n()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var h,g,n;e.ru=function(){this.pipeline.reset(),this.pipeline.add(e.ru.trimmer,e.ru.stopWordFilter,e.ru.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.ru.stemmer))},e.ru.wordCharacters="Ѐ-҄҇-ԯᴫᵸⷠ-ⷿꙀ-ꚟ︮︯",e.ru.trimmer=e.trimmerSupport.generateTrimmer(e.ru.wordCharacters),e.Pipeline.registerFunction(e.ru.trimmer,"trimmer-ru"),e.ru.stemmer=(h=e.stemmerSupport.Among,g=e.stemmerSupport.SnowballProgram,n=new function(){var n,e,r=[new h("в",-1,1),new h("ив",0,2),new h("ыв",0,2),new h("вши",-1,1),new h("ивши",3,2),new h("ывши",3,2),new h("вшись",-1,1),new h("ившись",6,2),new h("ывшись",6,2)],t=[new h("ее",-1,1),new h("ие",-1,1),new h("ое",-1,1),new h("ые",-1,1),new h("ими",-1,1),new h("ыми",-1,1),new h("ей",-1,1),new h("ий",-1,1),new h("ой",-1,1),new h("ый",-1,1),new h("ем",-1,1),new h("им",-1,1),new h("ом",-1,1),new h("ым",-1,1),new h("его",-1,1),new h("ого",-1,1),new h("ему",-1,1),new h("ому",-1,1),new h("их",-1,1),new h("ых",-1,1),new h("ею",-1,1),new h("ою",-1,1),new h("ую",-1,1),new h("юю",-1,1),new h("ая",-1,1),new h("яя",-1,1)],w=[new h("ем",-1,1),new h("нн",-1,1),new h("вш",-1,1),new h("ивш",2,2),new h("ывш",2,2),new h("щ",-1,1),new h("ющ",5,1),new h("ующ",6,2)],i=[new h("сь",-1,1),new h("ся",-1,1)],u=[new h("ла",-1,1),new h("ила",0,2),new h("ыла",0,2),new h("на",-1,1),new h("ена",3,2),new h("ете",-1,1),new h("ите",-1,2),new h("йте",-1,1),new h("ейте",7,2),new h("уйте",7,2),new h("ли",-1,1),new h("или",10,2),new h("ыли",10,2),new h("й",-1,1),new h("ей",13,2),new h("уй",13,2),new h("л",-1,1),new h("ил",16,2),new h("ыл",16,2),new h("ем",-1,1),new h("им",-1,2),new h("ым",-1,2),new h("н",-1,1),new h("ен",22,2),new h("ло",-1,1),new h("ило",24,2),new h("ыло",24,2),new h("но",-1,1),new h("ено",27,2),new h("нно",27,1),new h("ет",-1,1),new h("ует",30,2),new h("ит",-1,2),new h("ыт",-1,2),new h("ют",-1,1),new h("уют",34,2),new h("ят",-1,2),new h("ны",-1,1),new h("ены",37,2),new h("ть",-1,1),new h("ить",39,2),new h("ыть",39,2),new h("ешь",-1,1),new h("ишь",-1,2),new h("ю",-1,2),new h("ую",44,2)],s=[new h("а",-1,1),new h("ев",-1,1),new h("ов",-1,1),new h("е",-1,1),new h("ие",3,1),new h("ье",3,1),new h("и",-1,1),new h("еи",6,1),new h("ии",6,1),new h("ами",6,1),new h("ями",6,1),new h("иями",10,1),new h("й",-1,1),new h("ей",12,1),new h("ией",13,1),new h("ий",12,1),new h("ой",12,1),new h("ам",-1,1),new h("ем",-1,1),new h("ием",18,1),new h("ом",-1,1),new h("ям",-1,1),new h("иям",21,1),new h("о",-1,1),new h("у",-1,1),new h("ах",-1,1),new h("ях",-1,1),new h("иях",26,1),new h("ы",-1,1),new h("ь",-1,1),new h("ю",-1,1),new h("ию",30,1),new h("ью",30,1),new h("я",-1,1),new h("ия",33,1),new h("ья",33,1)],o=[new h("ост",-1,1),new h("ость",-1,1)],c=[new h("ейше",-1,1),new h("н",-1,2),new h("ейш",-1,1),new h("ь",-1,3)],m=[33,65,8,232],l=new g;function f(){for(;!l.in_grouping(m,1072,1103);){if(l.cursor>=l.limit)return!1;l.cursor++}return!0}function a(){for(;!l.out_grouping(m,1072,1103);){if(l.cursor>=l.limit)return!1;l.cursor++}return!0}function p(e,n){var r,t;if(l.ket=l.cursor,r=l.find_among_b(e,n)){switch(l.bra=l.cursor,r){case 1:if(t=l.limit-l.cursor,!l.eq_s_b(1,"а")&&(l.cursor=l.limit-t,!l.eq_s_b(1,"я")))return!1;case 2:l.slice_del()}return!0}return!1}function d(e,n){var r;return l.ket=l.cursor,!!(r=l.find_among_b(e,n))&&(l.bra=l.cursor,1==r&&l.slice_del(),!0)}function _(){return!!d(t,26)&&(p(w,8),!0)}function b(){var e;l.ket=l.cursor,(e=l.find_among_b(o,2))&&(l.bra=l.cursor,n<=l.cursor&&1==e&&l.slice_del())}this.setCurrent=function(e){l.setCurrent(e)},this.getCurrent=function(){return l.getCurrent()},this.stem=function(){return e=l.limit,n=e,f()&&(e=l.cursor,a()&&f()&&a()&&(n=l.cursor)),l.cursor=l.limit,!(l.cursor>3]&1<<(7&s))return this.cursor++,!0}return!1},in_grouping_b:function(r,t,i){if(this.cursor>this.limit_backward){var s=b.charCodeAt(this.cursor-1);if(s<=i&&t<=s&&r[(s-=t)>>3]&1<<(7&s))return this.cursor--,!0}return!1},out_grouping:function(r,t,i){if(this.cursor>3]&1<<(7&s)))return this.cursor++,!0}return!1},out_grouping_b:function(r,t,i){if(this.cursor>this.limit_backward){var s=b.charCodeAt(this.cursor-1);if(i>3]&1<<(7&s)))return this.cursor--,!0}return!1},eq_s:function(r,t){if(this.limit-this.cursor>1),a=0,f=u=(l=r[i]).s_size){if(this.cursor=e+l.s_size,!l.method)return l.result;var m=l.method();if(this.cursor=e+l.s_size,m)return l.result}if((i=l.substring_i)<0)return 0}},find_among_b:function(r,t){for(var i=0,s=t,e=this.cursor,n=this.limit_backward,u=0,o=0,h=!1;;){for(var c=i+(s-i>>1),a=0,f=u=(_=r[i]).s_size){if(this.cursor=e-_.s_size,!_.method)return _.result;var m=_.method();if(this.cursor=e-_.s_size,m)return _.result}if((i=_.substring_i)<0)return 0}},replace_s:function(r,t,i){var s=i.length-(t-r);return b=b.substring(0,r)+i+b.substring(t),this.limit+=s,this.cursor>=t?this.cursor+=s:this.cursor>r&&(this.cursor=r),s},slice_check:function(){if(this.bra<0||this.bra>this.ket||this.ket>this.limit||this.limit>b.length)throw"faulty slice operation"},slice_from:function(r){this.slice_check(),this.replace_s(this.bra,this.ket,r)},slice_del:function(){this.slice_from("")},insert:function(r,t,i){var s=this.replace_s(r,t,i);r<=this.bra&&(this.bra+=s),r<=this.ket&&(this.ket+=s)},slice_to:function(){return this.slice_check(),b.substring(this.bra,this.ket)},eq_v_b:function(r){return this.eq_s_b(r.length,r)}}}},r.trimmerSupport={generateTrimmer:function(r){var t=new RegExp("^[^"+r+"]+"),i=new RegExp("[^"+r+"]+$");return function(r){return"function"==typeof r.update?r.update(function(r){return r.replace(t,"").replace(i,"")}):r.replace(t,"").replace(i,"")}}}}}); \ No newline at end of file diff --git a/_static/javascripts/lunr/lunr.sv.js b/_static/javascripts/lunr/lunr.sv.js new file mode 100644 index 0000000000..6daf5f9d80 --- /dev/null +++ b/_static/javascripts/lunr/lunr.sv.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r,l,n;e.sv=function(){this.pipeline.reset(),this.pipeline.add(e.sv.trimmer,e.sv.stopWordFilter,e.sv.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.sv.stemmer))},e.sv.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.sv.trimmer=e.trimmerSupport.generateTrimmer(e.sv.wordCharacters),e.Pipeline.registerFunction(e.sv.trimmer,"trimmer-sv"),e.sv.stemmer=(r=e.stemmerSupport.Among,l=e.stemmerSupport.SnowballProgram,n=new function(){var n,t,i=[new r("a",-1,1),new r("arna",0,1),new r("erna",0,1),new r("heterna",2,1),new r("orna",0,1),new r("ad",-1,1),new r("e",-1,1),new r("ade",6,1),new r("ande",6,1),new r("arne",6,1),new r("are",6,1),new r("aste",6,1),new r("en",-1,1),new r("anden",12,1),new r("aren",12,1),new r("heten",12,1),new r("ern",-1,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",18,1),new r("or",-1,1),new r("s",-1,2),new r("as",21,1),new r("arnas",22,1),new r("ernas",22,1),new r("ornas",22,1),new r("es",21,1),new r("ades",26,1),new r("andes",26,1),new r("ens",21,1),new r("arens",29,1),new r("hetens",29,1),new r("erns",21,1),new r("at",-1,1),new r("andet",-1,1),new r("het",-1,1),new r("ast",-1,1)],s=[new r("dd",-1,-1),new r("gd",-1,-1),new r("nn",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1),new r("tt",-1,-1)],a=[new r("ig",-1,1),new r("lig",0,1),new r("els",-1,1),new r("fullt",-1,3),new r("löst",-1,2)],o=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,24,0,32],u=[119,127,149],m=new l;this.setCurrent=function(e){m.setCurrent(e)},this.getCurrent=function(){return m.getCurrent()},this.stem=function(){var e,r=m.cursor;return function(){var e,r=m.cursor+3;if(t=m.limit,0<=r||r<=m.limit){for(n=r;;){if(e=m.cursor,m.in_grouping(o,97,246)){m.cursor=e;break}if(m.cursor=e,m.cursor>=m.limit)return;m.cursor++}for(;!m.out_grouping(o,97,246);){if(m.cursor>=m.limit)return;m.cursor++}(t=m.cursor)=t&&(m.limit_backward=t,m.cursor=m.limit,m.ket=m.cursor,e=m.find_among_b(i,37),m.limit_backward=r,e))switch(m.bra=m.cursor,e){case 1:m.slice_del();break;case 2:m.in_grouping_b(u,98,121)&&m.slice_del()}}(),m.cursor=m.limit,e=m.limit_backward,m.cursor>=t&&(m.limit_backward=t,m.cursor=m.limit,m.find_among_b(s,7)&&(m.cursor=m.limit,m.ket=m.cursor,m.cursor>m.limit_backward&&(m.bra=--m.cursor,m.slice_del())),m.limit_backward=e),m.cursor=m.limit,function(){var e,r;if(m.cursor>=t){if(r=m.limit_backward,m.limit_backward=t,m.cursor=m.limit,m.ket=m.cursor,e=m.find_among_b(a,5))switch(m.bra=m.cursor,e){case 1:m.slice_del();break;case 2:m.slice_from("lös");break;case 3:m.slice_from("full")}m.limit_backward=r}}(),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}),e.Pipeline.registerFunction(e.sv.stemmer,"stemmer-sv"),e.sv.stopWordFilter=e.generateStopWordFilter("alla allt att av blev bli blir blivit de dem den denna deras dess dessa det detta dig din dina ditt du där då efter ej eller en er era ert ett från för ha hade han hans har henne hennes hon honom hur här i icke ingen inom inte jag ju kan kunde man med mellan men mig min mina mitt mot mycket ni nu när någon något några och om oss på samma sedan sig sin sina sitta själv skulle som så sådan sådana sådant till under upp ut utan vad var vara varför varit varje vars vart vem vi vid vilka vilkas vilken vilket vår våra vårt än är åt över".split(" ")),e.Pipeline.registerFunction(e.sv.stopWordFilter,"stopWordFilter-sv")}}); \ No newline at end of file diff --git a/_static/javascripts/lunr/lunr.th.js b/_static/javascripts/lunr/lunr.th.js new file mode 100644 index 0000000000..ee8ef373a0 --- /dev/null +++ b/_static/javascripts/lunr/lunr.th.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(t){if(void 0===t)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===t.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var i="2"==t.version[0];t.th=function(){this.pipeline.reset(),this.pipeline.add(t.th.trimmer),i?this.tokenizer=t.th.tokenizer:(t.tokenizer&&(t.tokenizer=t.th.tokenizer),this.tokenizerFn&&(this.tokenizerFn=t.th.tokenizer))},t.th.wordCharacters="[฀-๿]",t.th.trimmer=t.trimmerSupport.generateTrimmer(t.th.wordCharacters),t.Pipeline.registerFunction(t.th.trimmer,"trimmer-th");var n=t.wordcut;n.init(),t.th.tokenizer=function(e){if(!arguments.length||null==e||null==e)return[];if(Array.isArray(e))return e.map(function(e){return i?new t.Token(e):e});var r=e.toString().replace(/^\s+/,"");return n.cut(r).split("|")}}}); \ No newline at end of file diff --git a/_static/javascripts/lunr/lunr.tr.js b/_static/javascripts/lunr/lunr.tr.js new file mode 100644 index 0000000000..e8fb5a7df6 --- /dev/null +++ b/_static/javascripts/lunr/lunr.tr.js @@ -0,0 +1 @@ +!function(r,i){"function"==typeof define&&define.amd?define(i):"object"==typeof exports?module.exports=i():i()(r.lunr)}(this,function(){return function(r){if(void 0===r)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===r.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var mr,dr,i;r.tr=function(){this.pipeline.reset(),this.pipeline.add(r.tr.trimmer,r.tr.stopWordFilter,r.tr.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(r.tr.stemmer))},r.tr.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",r.tr.trimmer=r.trimmerSupport.generateTrimmer(r.tr.wordCharacters),r.Pipeline.registerFunction(r.tr.trimmer,"trimmer-tr"),r.tr.stemmer=(mr=r.stemmerSupport.Among,dr=r.stemmerSupport.SnowballProgram,i=new function(){var t,r=[new mr("m",-1,-1),new mr("n",-1,-1),new mr("miz",-1,-1),new mr("niz",-1,-1),new mr("muz",-1,-1),new mr("nuz",-1,-1),new mr("müz",-1,-1),new mr("nüz",-1,-1),new mr("mız",-1,-1),new mr("nız",-1,-1)],i=[new mr("leri",-1,-1),new mr("ları",-1,-1)],e=[new mr("ni",-1,-1),new mr("nu",-1,-1),new mr("nü",-1,-1),new mr("nı",-1,-1)],n=[new mr("in",-1,-1),new mr("un",-1,-1),new mr("ün",-1,-1),new mr("ın",-1,-1)],u=[new mr("a",-1,-1),new mr("e",-1,-1)],o=[new mr("na",-1,-1),new mr("ne",-1,-1)],s=[new mr("da",-1,-1),new mr("ta",-1,-1),new mr("de",-1,-1),new mr("te",-1,-1)],c=[new mr("nda",-1,-1),new mr("nde",-1,-1)],l=[new mr("dan",-1,-1),new mr("tan",-1,-1),new mr("den",-1,-1),new mr("ten",-1,-1)],a=[new mr("ndan",-1,-1),new mr("nden",-1,-1)],m=[new mr("la",-1,-1),new mr("le",-1,-1)],d=[new mr("ca",-1,-1),new mr("ce",-1,-1)],f=[new mr("im",-1,-1),new mr("um",-1,-1),new mr("üm",-1,-1),new mr("ım",-1,-1)],b=[new mr("sin",-1,-1),new mr("sun",-1,-1),new mr("sün",-1,-1),new mr("sın",-1,-1)],w=[new mr("iz",-1,-1),new mr("uz",-1,-1),new mr("üz",-1,-1),new mr("ız",-1,-1)],_=[new mr("siniz",-1,-1),new mr("sunuz",-1,-1),new mr("sünüz",-1,-1),new mr("sınız",-1,-1)],k=[new mr("lar",-1,-1),new mr("ler",-1,-1)],p=[new mr("niz",-1,-1),new mr("nuz",-1,-1),new mr("nüz",-1,-1),new mr("nız",-1,-1)],g=[new mr("dir",-1,-1),new mr("tir",-1,-1),new mr("dur",-1,-1),new mr("tur",-1,-1),new mr("dür",-1,-1),new mr("tür",-1,-1),new mr("dır",-1,-1),new mr("tır",-1,-1)],y=[new mr("casına",-1,-1),new mr("cesine",-1,-1)],z=[new mr("di",-1,-1),new mr("ti",-1,-1),new mr("dik",-1,-1),new mr("tik",-1,-1),new mr("duk",-1,-1),new mr("tuk",-1,-1),new mr("dük",-1,-1),new mr("tük",-1,-1),new mr("dık",-1,-1),new mr("tık",-1,-1),new mr("dim",-1,-1),new mr("tim",-1,-1),new mr("dum",-1,-1),new mr("tum",-1,-1),new mr("düm",-1,-1),new mr("tüm",-1,-1),new mr("dım",-1,-1),new mr("tım",-1,-1),new mr("din",-1,-1),new mr("tin",-1,-1),new mr("dun",-1,-1),new mr("tun",-1,-1),new mr("dün",-1,-1),new mr("tün",-1,-1),new mr("dın",-1,-1),new mr("tın",-1,-1),new mr("du",-1,-1),new mr("tu",-1,-1),new mr("dü",-1,-1),new mr("tü",-1,-1),new mr("dı",-1,-1),new mr("tı",-1,-1)],h=[new mr("sa",-1,-1),new mr("se",-1,-1),new mr("sak",-1,-1),new mr("sek",-1,-1),new mr("sam",-1,-1),new mr("sem",-1,-1),new mr("san",-1,-1),new mr("sen",-1,-1)],v=[new mr("miş",-1,-1),new mr("muş",-1,-1),new mr("müş",-1,-1),new mr("mış",-1,-1)],q=[new mr("b",-1,1),new mr("c",-1,2),new mr("d",-1,3),new mr("ğ",-1,4)],C=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,8,0,0,0,0,0,0,1],P=[1,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,1],F=[65],S=[65],W=[["a",[1,64,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],97,305],["e",[17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,130],101,252],["ı",[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],97,305],["i",[17],101,105],["o",F,111,117],["ö",S,246,252],["u",F,111,117]],L=new dr;function x(r,i,e){for(;;){var n=L.limit-L.cursor;if(L.in_grouping_b(r,i,e)){L.cursor=L.limit-n;break}if(L.cursor=L.limit-n,L.cursor<=L.limit_backward)return!1;L.cursor--}return!0}function A(){var r,i;r=L.limit-L.cursor,x(C,97,305);for(var e=0;eL.limit_backward&&(L.cursor--,e=L.limit-L.cursor,i()))?(L.cursor=L.limit-e,!0):(L.cursor=L.limit-n,r()?(L.cursor=L.limit-n,!1):(L.cursor=L.limit-n,!(L.cursor<=L.limit_backward)&&(L.cursor--,!!i()&&(L.cursor=L.limit-n,!0))))}function j(r){return E(r,function(){return L.in_grouping_b(C,97,305)})}function T(){return j(function(){return L.eq_s_b(1,"n")})}function Z(){return j(function(){return L.eq_s_b(1,"y")})}function B(){return L.find_among_b(r,10)&&E(function(){return L.in_grouping_b(P,105,305)},function(){return L.out_grouping_b(C,97,305)})}function D(){return A()&&L.in_grouping_b(P,105,305)&&j(function(){return L.eq_s_b(1,"s")})}function G(){return L.find_among_b(i,2)}function H(){return A()&&L.find_among_b(n,4)&&T()}function I(){return A()&&L.find_among_b(s,4)}function J(){return A()&&L.find_among_b(c,2)}function K(){return A()&&L.find_among_b(f,4)&&Z()}function M(){return A()&&L.find_among_b(b,4)}function N(){return A()&&L.find_among_b(w,4)&&Z()}function O(){return L.find_among_b(_,4)}function Q(){return A()&&L.find_among_b(k,2)}function R(){return A()&&L.find_among_b(g,8)}function U(){return A()&&L.find_among_b(z,32)&&Z()}function V(){return L.find_among_b(h,8)&&Z()}function X(){return A()&&L.find_among_b(v,4)&&Z()}function Y(){var r=L.limit-L.cursor;return!(X()||(L.cursor=L.limit-r,U()||(L.cursor=L.limit-r,V()||(L.cursor=L.limit-r,L.eq_s_b(3,"ken")&&Z()))))}function $(){if(L.find_among_b(y,2)){var r=L.limit-L.cursor;if(O()||(L.cursor=L.limit-r,Q()||(L.cursor=L.limit-r,K()||(L.cursor=L.limit-r,M()||(L.cursor=L.limit-r,N()||(L.cursor=L.limit-r))))),X())return!1}return!0}function rr(){if(!A()||!L.find_among_b(p,4))return!0;var r=L.limit-L.cursor;return!U()&&(L.cursor=L.limit-r,!V())}function ir(){var r,i,e,n=L.limit-L.cursor;if(L.ket=L.cursor,t=!0,Y()&&(L.cursor=L.limit-n,$()&&(L.cursor=L.limit-n,function(){if(Q()){L.bra=L.cursor,L.slice_del();var r=L.limit-L.cursor;return L.ket=L.cursor,R()||(L.cursor=L.limit-r,U()||(L.cursor=L.limit-r,V()||(L.cursor=L.limit-r,X()||(L.cursor=L.limit-r)))),t=!1}return!0}()&&(L.cursor=L.limit-n,rr()&&(L.cursor=L.limit-n,e=L.limit-L.cursor,!(O()||(L.cursor=L.limit-e,N()||(L.cursor=L.limit-e,M()||(L.cursor=L.limit-e,K()))))||(L.bra=L.cursor,L.slice_del(),i=L.limit-L.cursor,L.ket=L.cursor,X()||(L.cursor=L.limit-i),0)))))){if(L.cursor=L.limit-n,!R())return;L.bra=L.cursor,L.slice_del(),L.ket=L.cursor,r=L.limit-L.cursor,O()||(L.cursor=L.limit-r,Q()||(L.cursor=L.limit-r,K()||(L.cursor=L.limit-r,M()||(L.cursor=L.limit-r,N()||(L.cursor=L.limit-r))))),X()||(L.cursor=L.limit-r)}L.bra=L.cursor,L.slice_del()}function er(){var r,i,e,n;if(L.ket=L.cursor,L.eq_s_b(2,"ki")){if(r=L.limit-L.cursor,I())return L.bra=L.cursor,L.slice_del(),i=L.limit-L.cursor,L.ket=L.cursor,Q()?(L.bra=L.cursor,L.slice_del(),er()):(L.cursor=L.limit-i,B()&&(L.bra=L.cursor,L.slice_del(),L.ket=L.cursor,Q()&&(L.bra=L.cursor,L.slice_del(),er()))),!0;if(L.cursor=L.limit-r,H()){if(L.bra=L.cursor,L.slice_del(),L.ket=L.cursor,e=L.limit-L.cursor,G())L.bra=L.cursor,L.slice_del();else{if(L.cursor=L.limit-e,L.ket=L.cursor,!B()&&(L.cursor=L.limit-e,!D()&&(L.cursor=L.limit-e,!er())))return!0;L.bra=L.cursor,L.slice_del(),L.ket=L.cursor,Q()&&(L.bra=L.cursor,L.slice_del(),er())}return!0}if(L.cursor=L.limit-r,J()){if(n=L.limit-L.cursor,G())L.bra=L.cursor,L.slice_del();else if(L.cursor=L.limit-n,D())L.bra=L.cursor,L.slice_del(),L.ket=L.cursor,Q()&&(L.bra=L.cursor,L.slice_del(),er());else if(L.cursor=L.limit-n,!er())return!1;return!0}}return!1}function nr(r){if(L.ket=L.cursor,!J()&&(L.cursor=L.limit-r,!A()||!L.find_among_b(o,2)))return!1;var i=L.limit-L.cursor;if(G())L.bra=L.cursor,L.slice_del();else if(L.cursor=L.limit-i,D())L.bra=L.cursor,L.slice_del(),L.ket=L.cursor,Q()&&(L.bra=L.cursor,L.slice_del(),er());else if(L.cursor=L.limit-i,!er())return!1;return!0}function tr(r){if(L.ket=L.cursor,!(A()&&L.find_among_b(a,2)||(L.cursor=L.limit-r,A()&&L.find_among_b(e,4))))return!1;var i=L.limit-L.cursor;return!(!D()&&(L.cursor=L.limit-i,!G()))&&(L.bra=L.cursor,L.slice_del(),L.ket=L.cursor,Q()&&(L.bra=L.cursor,L.slice_del(),er()),!0)}function ur(){var r,i=L.limit-L.cursor;return L.ket=L.cursor,!!(H()||(L.cursor=L.limit-i,A()&&L.find_among_b(m,2)&&Z()))&&(L.bra=L.cursor,L.slice_del(),r=L.limit-L.cursor,L.ket=L.cursor,!(!Q()||(L.bra=L.cursor,L.slice_del(),!er()))||(L.cursor=L.limit-r,L.ket=L.cursor,(B()||(L.cursor=L.limit-r,D()||(L.cursor=L.limit-r,er())))&&(L.bra=L.cursor,L.slice_del(),L.ket=L.cursor,Q()&&(L.bra=L.cursor,L.slice_del(),er())),!0))}function or(){var r,i,e=L.limit-L.cursor;if(L.ket=L.cursor,!(I()||(L.cursor=L.limit-e,A()&&L.in_grouping_b(P,105,305)&&Z()||(L.cursor=L.limit-e,A()&&L.find_among_b(u,2)&&Z()))))return!1;if(L.bra=L.cursor,L.slice_del(),L.ket=L.cursor,r=L.limit-L.cursor,B())L.bra=L.cursor,L.slice_del(),i=L.limit-L.cursor,L.ket=L.cursor,Q()||(L.cursor=L.limit-i);else if(L.cursor=L.limit-r,!Q())return!0;return L.bra=L.cursor,L.slice_del(),L.ket=L.cursor,er(),!0}function sr(){var r,i,e=L.limit-L.cursor;if(L.ket=L.cursor,Q())return L.bra=L.cursor,L.slice_del(),void er();if(L.cursor=L.limit-e,L.ket=L.cursor,A()&&L.find_among_b(d,2)&&T())if(L.bra=L.cursor,L.slice_del(),r=L.limit-L.cursor,L.ket=L.cursor,G())L.bra=L.cursor,L.slice_del();else{if(L.cursor=L.limit-r,L.ket=L.cursor,!B()&&(L.cursor=L.limit-r,!D())){if(L.cursor=L.limit-r,L.ket=L.cursor,!Q())return;if(L.bra=L.cursor,L.slice_del(),!er())return}L.bra=L.cursor,L.slice_del(),L.ket=L.cursor,Q()&&(L.bra=L.cursor,L.slice_del(),er())}else if(L.cursor=L.limit-e,!nr(e)&&(L.cursor=L.limit-e,!tr(e))){if(L.cursor=L.limit-e,L.ket=L.cursor,A()&&L.find_among_b(l,4))return L.bra=L.cursor,L.slice_del(),L.ket=L.cursor,i=L.limit-L.cursor,void(B()?(L.bra=L.cursor,L.slice_del(),L.ket=L.cursor,Q()&&(L.bra=L.cursor,L.slice_del(),er())):(L.cursor=L.limit-i,Q()?(L.bra=L.cursor,L.slice_del()):L.cursor=L.limit-i,er()));if(L.cursor=L.limit-e,!ur()){if(L.cursor=L.limit-e,G())return L.bra=L.cursor,void L.slice_del();L.cursor=L.limit-e,er()||(L.cursor=L.limit-e,or()||(L.cursor=L.limit-e,L.ket=L.cursor,(B()||(L.cursor=L.limit-e,D()))&&(L.bra=L.cursor,L.slice_del(),L.ket=L.cursor,Q()&&(L.bra=L.cursor,L.slice_del(),er()))))}}}function cr(r,i,e){if(L.cursor=L.limit-r,function(){for(;;){var r=L.limit-L.cursor;if(L.in_grouping_b(C,97,305)){L.cursor=L.limit-r;break}if(L.cursor=L.limit-r,L.cursor<=L.limit_backward)return!1;L.cursor--}return!0}()){var n=L.limit-L.cursor;if(!L.eq_s_b(1,i)&&(L.cursor=L.limit-n,!L.eq_s_b(1,e)))return!0;L.cursor=L.limit-r;var t=L.cursor;return L.insert(L.cursor,L.cursor,e),L.cursor=t,!1}return!0}function lr(r,i,e){for(;!L.eq_s(i,e);){if(L.cursor>=L.limit)return!0;L.cursor++}return i!=L.limit||(L.cursor=r,!1)}function ar(){var r,i,e=L.cursor;return!(!lr(r=L.cursor,2,"ad")||!lr(L.cursor=r,5,"soyad"))&&(L.limit_backward=e,L.cursor=L.limit,i=L.limit-L.cursor,(L.eq_s_b(1,"d")||(L.cursor=L.limit-i,L.eq_s_b(1,"g")))&&cr(i,"a","ı")&&cr(i,"e","i")&&cr(i,"o","u")&&cr(i,"ö","ü"),L.cursor=L.limit,function(){var r;if(L.ket=L.cursor,r=L.find_among_b(q,4))switch(L.bra=L.cursor,r){case 1:L.slice_from("p");break;case 2:L.slice_from("ç");break;case 3:L.slice_from("t");break;case 4:L.slice_from("k")}}(),!0)}this.setCurrent=function(r){L.setCurrent(r)},this.getCurrent=function(){return L.getCurrent()},this.stem=function(){return!!(function(){for(var r,i=L.cursor,e=2;;){for(r=L.cursor;!L.in_grouping(C,97,305);){if(L.cursor>=L.limit)return L.cursor=r,!(0e&&(this._events[n].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[n].length),"function"==typeof console.trace&&console.trace()));return this},r.prototype.once=function(n,t){if(!a(t))throw TypeError("listener must be a function");var e=!1;function r(){this.removeListener(n,r),e||(e=!0,t.apply(this,arguments))}return r.listener=t,this.on(n,r),this},r.prototype.removeListener=function(n,t){var e,r,i,o;if(!a(t))throw TypeError("listener must be a function");if(!this._events||!this._events[n])return this;if(i=(e=this._events[n]).length,r=-1,e===t||a(e.listener)&&e.listener===t)delete this._events[n],this._events.removeListener&&this.emit("removeListener",n,t);else if(c(e)){for(o=i;0this.maxLength)return i();if(!this.stat&&p(this.cache,o)){var t=this.cache[o];if(Array.isArray(t)&&(t="DIR"),!n||"DIR"===t)return i(null,t);if(n&&"FILE"===t)return i()}var e=this.statCache[o];if(void 0!==e){if(!1===e)return i(null,e);var s=e.isDirectory()?"DIR":"FILE";return n&&"FILE"===s?i():i(null,s,e)}var a=this,c=d("stat\0"+o,function(n,e){{if(e&&e.isSymbolicLink())return u.stat(o,function(n,t){n?a._stat2(r,o,null,e,i):a._stat2(r,o,n,t,i)});a._stat2(r,o,n,e,i)}});c&&u.lstat(o,c)},b.prototype._stat2=function(n,t,e,r,i){if(e)return this.statCache[t]=!1,i();var o="/"===n.slice(-1);if(this.statCache[t]=r,"/"===t.slice(-1)&&!r.isDirectory())return i(null,!1,r);var s=r.isDirectory()?"DIR":"FILE";return this.cache[t]=this.cache[t]||s,o&&"DIR"!==s?i():i(null,s,r)}}).call(this,_("_process"))},{"./common.js":15,"./sync.js":17,_process:24,assert:9,events:14,fs:12,inflight:18,inherits:19,minimatch:20,once:21,path:22,"path-is-absolute":23,util:28}],17:[function(e,r,n){(function(i){(r.exports=n).GlobSync=h;var s=e("fs"),c=e("minimatch"),g=(c.Minimatch,e("./glob.js").Glob,e("util"),e("path")),u=e("assert"),l=e("path-is-absolute"),t=e("./common.js"),o=(t.alphasort,t.alphasorti,t.setopts),a=t.ownProp,f=t.childrenIgnored;function n(n,t){if("function"==typeof t||3===arguments.length)throw new TypeError("callback provided to sync glob\nSee: https://github.com/isaacs/node-glob/issues/167");return new h(n,t).found}function h(n,t){if(!n)throw new Error("must provide pattern");if("function"==typeof t||3===arguments.length)throw new TypeError("callback provided to sync glob\nSee: https://github.com/isaacs/node-glob/issues/167");if(!(this instanceof h))return new h(n,t);if(o(this,n,t),this.noprocess)return this;var e=this.minimatch.set.length;this.matches=new Array(e);for(var r=0;rthis.maxLength)return!1;if(!this.stat&&a(this.cache,t)){var r=this.cache[t];if(Array.isArray(r)&&(r="DIR"),!e||"DIR"===r)return r;if(e&&"FILE"===r)return!1}var i=this.statCache[t];if(!i){var o;try{o=s.lstatSync(t)}catch(n){return!1}if(o.isSymbolicLink())try{i=s.statSync(t)}catch(n){i=o}else i=o}r=(this.statCache[t]=i).isDirectory()?"DIR":"FILE";return this.cache[t]=this.cache[t]||r,(!e||"DIR"===r)&&r},h.prototype._mark=function(n){return t.mark(this,n)},h.prototype._makeAbs=function(n){return t.makeAbs(this,n)}}).call(this,e("_process"))},{"./common.js":15,"./glob.js":16,_process:24,assert:9,fs:12,minimatch:20,path:22,"path-is-absolute":23,util:28}],18:[function(t,r,n){(function(s){var n=t("wrappy"),a=Object.create(null),e=t("once");r.exports=n(function(n,t){return a[n]?(a[n].push(t),null):(a[n]=[t],o=n,e(function n(){var t=a[o],e=t.length,r=function(n){for(var t=n.length,e=[],r=0;re?(t.splice(0,e),s.nextTick(function(){n.apply(null,r)})):delete a[o]}}));var o})}).call(this,t("_process"))},{_process:24,once:21,wrappy:29}],19:[function(n,t,e){"function"==typeof Object.create?t.exports=function(n,t){n.super_=t,n.prototype=Object.create(t.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}})}:t.exports=function(n,t){n.super_=t;var e=function(){};e.prototype=t.prototype,n.prototype=new e,n.prototype.constructor=n}},{}],20:[function(n,t,e){(t.exports=s).Minimatch=i;var u={sep:"/"};try{u=n("path")}catch(n){}var M=s.GLOBSTAR=i.GLOBSTAR={},r=n("brace-expansion"),C={"!":{open:"(?:(?!(?:",close:"))[^/]*?)"},"?":{open:"(?:",close:")?"},"+":{open:"(?:",close:")+"},"*":{open:"(?:",close:")*"},"@":{open:"(?:",close:")"}},P="[^/]",z=P+"*?",B="().*{}+?[]^$\\!".split("").reduce(function(n,t){return n[t]=!0,n},{});var l=/\/+/;function o(t,e){t=t||{},e=e||{};var r={};return Object.keys(e).forEach(function(n){r[n]=e[n]}),Object.keys(t).forEach(function(n){r[n]=t[n]}),r}function s(n,t,e){if("string"!=typeof t)throw new TypeError("glob pattern string required");return e||(e={}),!(!e.nocomment&&"#"===t.charAt(0))&&(""===t.trim()?""===n:new i(t,e).match(n))}function i(n,t){if(!(this instanceof i))return new i(n,t);if("string"!=typeof n)throw new TypeError("glob pattern string required");t||(t={}),n=n.trim(),"/"!==u.sep&&(n=n.split(u.sep).join("/")),this.options=t,this.set=[],this.pattern=n,this.regexp=null,this.negate=!1,this.comment=!1,this.empty=!1,this.make()}function a(n,t){if(t||(t=this instanceof i?this.options:{}),void 0===(n=void 0===n?this.pattern:n))throw new TypeError("undefined pattern");return t.nobrace||!n.match(/\{.*\}/)?[n]:r(n)}s.filter=function(r,i){return i=i||{},function(n,t,e){return s(n,r,i)}},s.defaults=function(r){if(!r||!Object.keys(r).length)return s;var i=s,n=function(n,t,e){return i.minimatch(n,t,o(r,e))};return n.Minimatch=function(n,t){return new i.Minimatch(n,o(r,t))},n},i.defaults=function(n){return n&&Object.keys(n).length?s.defaults(n).Minimatch:i},i.prototype.debug=function(){},i.prototype.make=function(){if(this._made)return;var n=this.pattern,t=this.options;if(!t.nocomment&&"#"===n.charAt(0))return void(this.comment=!0);if(!n)return void(this.empty=!0);this.parseNegate();var e=this.globSet=this.braceExpand();t.debug&&(this.debug=console.error);this.debug(this.pattern,e),e=this.globParts=e.map(function(n){return n.split(l)}),this.debug(this.pattern,e),e=e.map(function(n,t,e){return n.map(this.parse,this)},this),this.debug(this.pattern,e),e=e.filter(function(n){return-1===n.indexOf(!1)}),this.debug(this.pattern,e),this.set=e},i.prototype.parseNegate=function(){var n=this.pattern,t=!1,e=this.options,r=0;if(e.nonegate)return;for(var i=0,o=n.length;i>> no match, partial?",n,f,t,h),f!==s))}if("string"==typeof u?(c=r.nocase?l.toLowerCase()===u.toLowerCase():l===u,this.debug("string match",u,l,c)):(c=l.match(u),this.debug("pattern match",u,l,c)),!c)return!1}if(i===s&&o===a)return!0;if(i===s)return e;if(o===a)return i===s-1&&""===n[i];throw new Error("wtf?")}},{"brace-expansion":11,path:22}],21:[function(n,t,e){var r=n("wrappy");function i(n){var t=function(){return t.called?t.value:(t.called=!0,t.value=n.apply(this,arguments))};return t.called=!1,t}function o(n){var t=function(){if(t.called)throw new Error(t.onceError);return t.called=!0,t.value=n.apply(this,arguments)},e=n.name||"Function wrapped with `once`";return t.onceError=e+" shouldn't be called more than once",t.called=!1,t}t.exports=r(i),t.exports.strict=r(o),i.proto=i(function(){Object.defineProperty(Function.prototype,"once",{value:function(){return i(this)},configurable:!0}),Object.defineProperty(Function.prototype,"onceStrict",{value:function(){return o(this)},configurable:!0})})},{wrappy:29}],22:[function(n,t,u){(function(i){function o(n,t){for(var e=0,r=n.length-1;0<=r;r--){var i=n[r];"."===i?n.splice(r,1):".."===i?(n.splice(r,1),e++):e&&(n.splice(r,1),e--)}if(t)for(;e--;e)n.unshift("..");return n}var t=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/,s=function(n){return t.exec(n).slice(1)};function a(n,t){if(n.filter)return n.filter(t);for(var e=[],r=0;r":">",'"':""","'":"'","`":"`"},D=d.invert(N),F=function(t){var e=function(n){return t[n]},n="(?:"+d.keys(t).join("|")+")",r=RegExp(n),i=RegExp(n,"g");return function(n){return n=null==n?"":""+n,r.test(n)?n.replace(i,e):n}};d.escape=F(N),d.unescape=F(D),d.result=function(n,t,e){var r=null==n?void 0:n[t];return void 0===r&&(r=e),d.isFunction(r)?r.call(n):r};var M=0;d.uniqueId=function(n){var t=++M+"";return n?n+t:t},d.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var C=/(.)^/,P={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},z=/\\|'|\r|\n|\u2028|\u2029/g,B=function(n){return"\\"+P[n]};d.template=function(o,n,t){!n&&t&&(n=t),n=d.defaults({},n,d.templateSettings);var e=RegExp([(n.escape||C).source,(n.interpolate||C).source,(n.evaluate||C).source].join("|")+"|$","g"),s=0,a="__p+='";o.replace(e,function(n,t,e,r,i){return a+=o.slice(s,i).replace(z,B),s=i+n.length,t?a+="'+\n((__t=("+t+"))==null?'':_.escape(__t))+\n'":e?a+="'+\n((__t=("+e+"))==null?'':__t)+\n'":r&&(a+="';\n"+r+"\n__p+='"),n}),a+="';\n",n.variable||(a="with(obj||{}){\n"+a+"}\n"),a="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+a+"return __p;\n";try{var r=new Function(n.variable||"obj","_",a)}catch(n){throw n.source=a,n}var i=function(n){return r.call(this,n,d)},c=n.variable||"obj";return i.source="function("+c+"){\n"+a+"}",i},d.chain=function(n){var t=d(n);return t._chain=!0,t};var U=function(n,t){return n._chain?d(t).chain():t};d.mixin=function(e){d.each(d.functions(e),function(n){var t=d[n]=e[n];d.prototype[n]=function(){var n=[this._wrapped];return i.apply(n,arguments),U(this,t.apply(d,n))}})},d.mixin(d),d.each(["pop","push","reverse","shift","sort","splice","unshift"],function(t){var e=r[t];d.prototype[t]=function(){var n=this._wrapped;return e.apply(n,arguments),"shift"!==t&&"splice"!==t||0!==n.length||delete n[0],U(this,n)}}),d.each(["concat","join","slice"],function(n){var t=r[n];d.prototype[n]=function(){return U(this,t.apply(this._wrapped,arguments))}}),d.prototype.value=function(){return this._wrapped},d.prototype.valueOf=d.prototype.toJSON=d.prototype.value,d.prototype.toString=function(){return""+this._wrapped}}).call(this)},{}],26:[function(n,t,e){arguments[4][19][0].apply(e,arguments)},{dup:19}],27:[function(n,t,e){t.exports=function(n){return n&&"object"==typeof n&&"function"==typeof n.copy&&"function"==typeof n.fill&&"function"==typeof n.readUInt8}},{}],28:[function(h,n,k){(function(r,i){var a=/%[sdj%]/g;k.format=function(n){if(!_(n)){for(var t=[],e=0;e elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + return typeof obj === "function" && typeof obj.nodeType !== "number"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + +var document = window.document; + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { + doc = doc || document; + + var i, val, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.5.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return flat( ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.5 + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://js.foundation/ + * + * Date: 2020-03-14 + */ +( function( window ) { +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ( {} ).hasOwnProperty, + arr = [], + pop = arr.pop, + pushNative = arr.push, + push = arr.push, + slice = arr.slice, + + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[ i ] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + + "ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + + // "Attribute values must be CSS identifiers [capture 5] + // or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + + "*" ), + rdescend = new RegExp( whitespace + "|>" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rhtml = /HTML$/i, + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + return nonHex ? + + // Strip the backslash prefix from a non-hex escape sequence + nonHex : + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + inDisabledFieldset = addCombinator( + function( elem ) { + return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + ( arr = slice.call( preferredDoc.childNodes ) ), + preferredDoc.childNodes + ); + + // Support: Android<4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + pushNative.apply( target, slice.call( els ) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + + // Can't trust NodeList.length + while ( ( target[ j++ ] = els[ i++ ] ) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + setDocument( context ); + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { + + // ID selector + if ( ( m = match[ 1 ] ) ) { + + // Document context + if ( nodeType === 9 ) { + if ( ( elem = context.getElementById( m ) ) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && ( elem = newContext.getElementById( m ) ) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[ 2 ] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && + + // Support: IE 8 only + // Exclude object elements + ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && + ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + if ( newContext !== context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); + } + newSelector = groups.join( "," ); + } + + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return ( cache[ key + " " ] = value ); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement( "fieldset" ); + + try { + return !!fn( el ); + } catch ( e ) { + return false; + } finally { + + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split( "|" ), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[ i ] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( ( cur = cur.nextSibling ) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return ( name === "input" || name === "button" ) && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + inDisabledFieldset( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction( function( argument ) { + argument = +argument; + return markFunction( function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); + } + } + } ); + } ); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + var namespace = elem.namespaceURI, + docElem = ( elem.ownerDocument || elem ).documentElement; + + // Support: IE <=8 + // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes + // https://bugs.jquery.com/ticket/4833 + return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, + // Safari 4 - 5 only, Opera <=11.6 - 12.x only + // IE/Edge & older browsers don't support the :scope pseudo-class. + // Support: Safari 6.0 only + // Safari 6.0 supports :scope but it's an alias of :root there. + support.scope = assert( function( el ) { + docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); + return typeof el.querySelectorAll !== "undefined" && + !el.querySelectorAll( ":scope fieldset div" ).length; + } ); + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert( function( el ) { + el.className = "i"; + return !el.getAttribute( "className" ); + } ); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert( function( el ) { + el.appendChild( document.createComment( "" ) ); + return !el.getElementsByTagName( "*" ).length; + } ); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert( function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + } ); + + // ID filter and find + if ( support.getById ) { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute( "id" ) === attrId; + }; + }; + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode( "id" ); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find[ "TAG" ] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert( function( el ) { + + var input; + + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll( "[selected]" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); + } + + // Support: Firefox <=3.6 - 5 only + // Old Firefox doesn't throw on a badly-escaped identifier. + el.querySelectorAll( "\\\f" ); + rbuggyQSA.push( "[\\r\\n\\f]" ); + } ); + + assert( function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement( "input" ); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll( "[name=d]" ).length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: Opera 10 - 11 only + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll( "*,:x" ); + rbuggyQSA.push( ",.*:" ); + } ); + } + + if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector ) ) ) ) { + + assert( function( el ) { + + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + } ); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + ) ); + } : + function( a, b ) { + if ( b ) { + while ( ( b = b.parentNode ) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { + + // Choose the first element that is related to our preferred document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( a == document || a.ownerDocument == preferredDoc && + contains( preferredDoc, a ) ) { + return -1; + } + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( b == document || b.ownerDocument == preferredDoc && + contains( preferredDoc, b ) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + return a == document ? -1 : + b == document ? 1 : + /* eslint-enable eqeqeq */ + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( ( cur = cur.parentNode ) ) { + ap.unshift( cur ); + } + cur = b; + while ( ( cur = cur.parentNode ) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[ i ] === bp[ i ] ) { + i++; + } + + return i ? + + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[ i ], bp[ i ] ) : + + // Otherwise nodes in our document sort first + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + ap[ i ] == preferredDoc ? -1 : + bp[ i ] == preferredDoc ? 1 : + /* eslint-enable eqeqeq */ + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + setDocument( elem ); + + if ( support.matchesSelector && documentIsHTML && + !nonnativeSelectorCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch ( e ) { + nonnativeSelectorCache( expr, true ); + } + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( context.ownerDocument || context ) != document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( elem.ownerDocument || elem ) != document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return ( sel + "" ).replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + + // If no nodeType, this is expected to be an array + while ( ( node = elem[ i++ ] ) ) { + + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[ 1 ] = match[ 1 ].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[ 3 ] = ( match[ 3 ] || match[ 4 ] || + match[ 5 ] || "" ).replace( runescape, funescape ); + + if ( match[ 2 ] === "~=" ) { + match[ 3 ] = " " + match[ 3 ] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[ 1 ] = match[ 1 ].toLowerCase(); + + if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { + + // nth-* requires argument + if ( !match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[ 4 ] = +( match[ 4 ] ? + match[ 5 ] + ( match[ 6 ] || 1 ) : + 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); + match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); + + // other types prohibit arguments + } else if ( match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[ 6 ] && match[ 2 ]; + + if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[ 3 ] ) { + match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + + // Get excess from tokenize (recursively) + ( excess = tokenize( unquoted, true ) ) && + + // advance to the next closing parenthesis + ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { + + // excess is a negative index + match[ 0 ] = match[ 0 ].slice( 0, excess ); + match[ 2 ] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { + return true; + } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + ( pattern = new RegExp( "(^|" + whitespace + + ")" + className + "(" + whitespace + "|$)" ) ) && classCache( + className, function( elem ) { + return pattern.test( + typeof elem.className === "string" && elem.className || + typeof elem.getAttribute !== "undefined" && + elem.getAttribute( "class" ) || + "" + ); + } ); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + /* eslint-disable max-len */ + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + /* eslint-enable max-len */ + + }; + }, + + "CHILD": function( type, what, _argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, _context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( ( node = node[ dir ] ) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( ( node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + + // Use previously-cached element index if available + if ( useCache ) { + + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + + // Use the same loop as above to seek `elem` from the start + while ( ( node = ++nodeIndex && node && node[ dir ] || + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || + ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction( function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[ i ] ); + seed[ idx ] = !( matches[ idx ] = matched[ i ] ); + } + } ) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + + // Potentially complex pseudos + "not": markFunction( function( selector ) { + + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction( function( seed, matches, _context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( ( elem = unmatched[ i ] ) ) { + seed[ i ] = !( matches[ i ] = elem ); + } + } + } ) : + function( elem, _context, xml ) { + input[ 0 ] = elem; + matcher( input, null, xml, results ); + + // Don't keep the element (issue #299) + input[ 0 ] = null; + return !results.pop(); + }; + } ), + + "has": markFunction( function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + } ), + + "contains": markFunction( function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; + }; + } ), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + + // lang value must be a valid identifier + if ( !ridentifier.test( lang || "" ) ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( ( elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); + return false; + }; + } ), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && + ( !document.hasFocus || document.hasFocus() ) && + !!( elem.type || elem.href || ~elem.tabIndex ); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return ( nodeName === "input" && !!elem.checked ) || + ( nodeName === "option" && !!elem.selected ); + }, + + "selected": function( elem ) { + + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + // eslint-disable-next-line no-unused-expressions + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos[ "empty" ]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( ( attr = elem.getAttribute( "type" ) ) == null || + attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo( function() { + return [ 0 ]; + } ), + + "last": createPositionalPseudo( function( _matchIndexes, length ) { + return [ length - 1 ]; + } ), + + "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + } ), + + "even": createPositionalPseudo( function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "odd": createPositionalPseudo( function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? + argument + length : + argument > length ? + length : + argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ) + } +}; + +Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || ( match = rcomma.exec( soFar ) ) ) { + if ( match ) { + + // Don't consume trailing commas as valid + soFar = soFar.slice( match[ 0 ].length ) || soFar; + } + groups.push( ( tokens = [] ) ); + } + + matched = false; + + // Combinators + if ( ( match = rcombinators.exec( soFar ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + + // Cast descendant combinators to space + type: match[ 0 ].replace( rtrim, " " ) + } ); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || + ( match = preFilters[ type ]( match ) ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + type: type, + matches: match + } ); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[ i ].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || + ( outerCache[ elem.uniqueID ] = {} ); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( ( oldCache = uniqueCache[ key ] ) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return ( newCache[ 2 ] = oldCache[ 2 ] ); + } else { + + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[ i ]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[ 0 ]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[ i ], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( ( elem = unmatched[ i ] ) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction( function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( + selector || "*", + context.nodeType ? [ context ] : context, + [] + ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( ( elem = temp[ i ] ) ) { + matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) ) { + + // Restore matcherIn since elem is not yet a final match + temp.push( ( matcherIn[ i ] = elem ) ); + } + } + postFinder( null, ( matcherOut = [] ), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) && + ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { + + seed[ temp ] = !( results[ temp ] = elem ); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + } ); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[ 0 ].type ], + implicitRelative = leadingRelative || Expr.relative[ " " ], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + ( checkContext = context ).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; + } else { + matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[ j ].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens + .slice( 0, i - 1 ) + .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), + + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), + len = elems.length; + + if ( outermost ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + outermostContext = context == document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( !context && elem.ownerDocument != document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( ( matcher = elementMatchers[ j++ ] ) ) { + if ( matcher( elem, context || document, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + + // They will have gone through all possible matchers + if ( ( elem = !matcher && elem ) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( ( matcher = setMatchers[ j++ ] ) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !( unmatched[ i ] || setMatched[ i ] ) ) { + setMatched[ i ] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[ i ] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( + selector, + matcherFromGroupMatchers( elementMatchers, setMatchers ) + ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( ( selector = compiled.selector || selector ) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[ 0 ] = match[ 0 ].slice( 0 ); + if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { + + context = ( Expr.find[ "ID" ]( token.matches[ 0 ] + .replace( runescape, funescape ), context ) || [] )[ 0 ]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[ i ]; + + // Abort if we hit a combinator + if ( Expr.relative[ ( type = token.type ) ] ) { + break; + } + if ( ( find = Expr.find[ type ] ) ) { + + // Search, expanding context for leading sibling combinators + if ( ( seed = find( + token.matches[ 0 ].replace( runescape, funescape ), + rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || + context + ) ) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert( function( el ) { + + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; +} ); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert( function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute( "href" ) === "#"; +} ) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + } ); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert( function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +} ) ) { + addHandle( "value", function( elem, _name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + } ); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert( function( el ) { + return el.getAttribute( "disabled" ) == null; +} ) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; + } + } ); +} + +return Sizzle; + +} )( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, _i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, _i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, _i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( elem.contentDocument != null && + + // Support: IE 11+ + // elements with no `data` attribute has an object + // `contentDocument` with a `null` prototype. + getProto( elem.contentDocument ) ) { + + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && toType( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( _i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( toType( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, _key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( _all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (#9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); + } else { + key = camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var documentElement = document.documentElement; + + + + var isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ); + }, + composed = { composed: true }; + + // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only + // Check attachment across shadow DOM boundaries when possible (gh-3504) + // Support: iOS 10.0-10.2 only + // Early iOS 10 versions support `attachShadow` but not `getRootNode`, + // leading to errors. We need to check for `getRootNode`. + if ( documentElement.getRootNode ) { + isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ) || + elem.getRootNode( composed ) === elem.ownerDocument; + }; + } +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + isAttached( elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, scale, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = elem.nodeType && + ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while ( maxIterations-- ) { + + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; + + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); + +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); + + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // Support: IE <=9 only + // IE <=9 replaces "; + support.option = !!div.lastChild; +} )(); + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// Support: IE <=9 only +if ( !support.option ) { + wrapMap.optgroup = wrapMap.option = [ 1, "" ]; +} + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, attached, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( toType( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + attached = isAttached( elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( attached ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 - 11+ +// focus() and blur() are asynchronous, except when they are no-op. +// So expect focus to be synchronous when the element is already active, +// and blur to be synchronous when the element is not already active. +// (focus and blur are always synchronous in other supported browsers, +// this just defines when we can count on it). +function expectSync( elem, type ) { + return ( elem === safeActiveElement() ) === ( type === "focus" ); +} + +// Support: IE <=9 only +// Accessing document.activeElement can throw unexpectedly +// https://bugs.jquery.com/ticket/13393 +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Only attach events to objects that accept data + if ( !acceptData( elem ) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = Object.create( null ); + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( nativeEvent ), + + handlers = ( + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // If the event is namespaced, then each handler is only invoked if it is + // specially universal or its namespaces are a superset of the event's. + if ( !event.rnamespace || handleObj.namespace === false || + event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + click: { + + // Utilize native event to ensure correct state for checkable inputs + setup: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Claim the first handler + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + // dataPriv.set( el, "click", ... ) + leverageNative( el, "click", returnTrue ); + } + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Force setup before triggering a click + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + leverageNative( el, "click" ); + } + + // Return non-false to allow normal event-path propagation + return true; + }, + + // For cross-browser consistency, suppress native .click() on links + // Also prevent it if we're currently inside a leveraged native-event stack + _default: function( event ) { + var target = event.target; + return rcheckableType.test( target.type ) && + target.click && nodeName( target, "input" ) && + dataPriv.get( target, "click" ) || + nodeName( target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +// Ensure the presence of an event listener that handles manually-triggered +// synthetic events by interrupting progress until reinvoked in response to +// *native* events that it fires directly, ensuring that state changes have +// already occurred before other listeners are invoked. +function leverageNative( el, type, expectSync ) { + + // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add + if ( !expectSync ) { + if ( dataPriv.get( el, type ) === undefined ) { + jQuery.event.add( el, type, returnTrue ); + } + return; + } + + // Register the controller as a special universal handler for all event namespaces + dataPriv.set( el, type, false ); + jQuery.event.add( el, type, { + namespace: false, + handler: function( event ) { + var notAsync, result, + saved = dataPriv.get( this, type ); + + if ( ( event.isTrigger & 1 ) && this[ type ] ) { + + // Interrupt processing of the outer synthetic .trigger()ed event + // Saved data should be false in such cases, but might be a leftover capture object + // from an async native handler (gh-4350) + if ( !saved.length ) { + + // Store arguments for use when handling the inner native event + // There will always be at least one argument (an event object), so this array + // will not be confused with a leftover capture object. + saved = slice.call( arguments ); + dataPriv.set( this, type, saved ); + + // Trigger the native event and capture its result + // Support: IE <=9 - 11+ + // focus() and blur() are asynchronous + notAsync = expectSync( this, type ); + this[ type ](); + result = dataPriv.get( this, type ); + if ( saved !== result || notAsync ) { + dataPriv.set( this, type, false ); + } else { + result = {}; + } + if ( saved !== result ) { + + // Cancel the outer synthetic event + event.stopImmediatePropagation(); + event.preventDefault(); + return result.value; + } + + // If this is an inner synthetic event for an event with a bubbling surrogate + // (focus or blur), assume that the surrogate already propagated from triggering the + // native event and prevent that from happening again here. + // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the + // bubbling surrogate propagates *after* the non-bubbling base), but that seems + // less bad than duplication. + } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { + event.stopPropagation(); + } + + // If this is a native event triggered above, everything is now in order + // Fire an inner synthetic event with the original arguments + } else if ( saved.length ) { + + // ...and capture the result + dataPriv.set( this, type, { + value: jQuery.event.trigger( + + // Support: IE <=9 - 11+ + // Extend with the prototype to reset the above stopImmediatePropagation() + jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), + saved.slice( 1 ), + this + ) + } ); + + // Abort handling of the native event + event.stopImmediatePropagation(); + } + } + } ); +} + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + code: true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { + jQuery.event.special[ type ] = { + + // Utilize native event if possible so blur/focus sequence is correct + setup: function() { + + // Claim the first handler + // dataPriv.set( this, "focus", ... ) + // dataPriv.set( this, "blur", ... ) + leverageNative( this, type, expectSync ); + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function() { + + // Force setup before trigger + leverageNative( this, type ); + + // Return non-false to allow normal event-path propagation + return true; + }, + + delegateType: delegateType + }; +} ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.get( src ); + events = pdataOld.events; + + if ( events ) { + dataPriv.remove( dest, "handle events" ); + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = flat( args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + valueIsFunction = isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( valueIsFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( valueIsFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl && !node.noModule ) { + jQuery._evalUrl( node.src, { + nonce: node.nonce || node.getAttribute( "nonce" ) + }, doc ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && isAttached( node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html; + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = isAttached( elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + +var swap = function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; + div.style.cssText = + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + + "margin:auto;border:1px;padding:1px;" + + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; + + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + // Support: Chrome <=64 + // Don't get tricked when zoom affects offsetWidth (gh-4029) + div.style.position = "absolute"; + scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableTrDimensionsVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend( support, { + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; + }, + + // Support: IE 9 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Behavior in IE 9 is more subtle than in newer versions & it passes + // some versions of this test; make sure not to make it pass there! + reliableTrDimensions: function() { + var table, tr, trChild, trStyle; + if ( reliableTrDimensionsVal == null ) { + table = document.createElement( "table" ); + tr = document.createElement( "tr" ); + trChild = document.createElement( "div" ); + + table.style.cssText = "position:absolute;left:-11111px"; + tr.style.height = "1px"; + trChild.style.height = "9px"; + + documentElement + .appendChild( table ) + .appendChild( tr ) + .appendChild( trChild ); + + trStyle = window.getComputedStyle( tr ); + reliableTrDimensionsVal = parseInt( trStyle.height ) > 3; + + documentElement.removeChild( table ); + } + return reliableTrDimensionsVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !isAttached( elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style, + vendorProps = {}; + +// Return a vendor-prefixed property or undefined +function vendorPropName( name ) { + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a potentially-mapped jQuery.cssProps or vendor prefixed property +function finalPropName( name ) { + var final = jQuery.cssProps[ name ] || vendorProps[ name ]; + + if ( final ) { + return final; + } + if ( name in emptyStyle ) { + return name; + } + return vendorProps[ name ] = vendorPropName( name ) || name; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }; + +function setPositiveNumber( _elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0; + + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin + if ( box === "margin" ) { + delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + } + + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { + + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + + // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter + // Use an explicit zero to avoid NaN (gh-3964) + ) ) || 0; + } + + return delta; +} + +function getWidthOrHeight( elem, dimension, extra ) { + + // Start with computed style + var styles = getStyles( elem ), + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). + // Fake content-box until we know it's needed to know the true value. + boxSizingNeeded = !support.boxSizingReliable() || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox, + + val = curCSS( elem, dimension, styles ), + offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if ( rnumnonpx.test( val ) ) { + if ( !extra ) { + return val; + } + val = "auto"; + } + + + // Support: IE 9 - 11 only + // Use offsetWidth/offsetHeight for when box sizing is unreliable. + // In those cases, the computed value can be trusted to be border-box. + if ( ( !support.boxSizingReliable() && isBorderBox || + + // Support: IE 10 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Interestingly, in some cases IE 9 doesn't suffer from this issue. + !support.reliableTrDimensions() && nodeName( elem, "tr" ) || + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + val === "auto" || + + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && + + // Make sure the element is visible & connected + elem.getClientRects().length ) { + + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Where available, offsetWidth/offsetHeight approximate border box dimensions. + // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the + // retrieved value as a content box dimension. + valueIsBorderBox = offsetProp in elem; + if ( valueIsBorderBox ) { + val = elem[ offsetProp ]; + } + } + + // Normalize "" and auto + val = parseFloat( val ) || 0; + + // Adjust for the element's box model + return ( val + + boxModelAdjustment( + elem, + dimension, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "gridArea": true, + "gridColumn": true, + "gridColumnEnd": true, + "gridColumnStart": true, + "gridRow": true, + "gridRowEnd": true, + "gridRowStart": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append + // "px" to a few hardcoded values. + if ( type === "number" && !isCustomProp ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( _i, dimension ) { + jQuery.cssHooks[ dimension ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = getStyles( elem ), + + // Only read styles.position if the test has a chance to fail + // to avoid forcing a reflow. + scrollboxSizeBuggy = !support.scrollboxSize() && + styles.position === "absolute", + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) + boxSizingNeeded = scrollboxSizeBuggy || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra ? + boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ) : + 0; + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && scrollboxSizeBuggy ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( prefix !== "margin" ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && ( + jQuery.cssHooks[ tween.prop ] || + tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = Date.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 15 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + result.stop.bind( result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = Date.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); + + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( isValidValue ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = classesToArray( value ); + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, valueIsFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + valueIsFunction = isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( valueIsFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +support.focusin = "onfocusin" in window; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + lastElement = cur; + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( + dataPriv.get( cur, "events" ) || Object.create( null ) + )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + + // Handle: regular nodes (via `this.ownerDocument`), window + // (via `this.document`) & document (via `this`). + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = { guid: Date.now() }; + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && toType( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + if ( a == null ) { + return ""; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( _i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() + " " ] = + ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) + .concat( match[ 2 ] ); + } + } + match = responseHeaders[ key.toLowerCase() + " " ]; + } + return match == null ? null : match.join( ", " ); + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 15 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available and should be processed, append data to url + if ( s.data && ( s.processData || typeof s.data === "string" ) ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Use a noop converter for missing script + if ( !isSuccess && jQuery.inArray( "script", s.dataTypes ) > -1 ) { + s.converters[ "text script" ] = function() {}; + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( _i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + +jQuery.ajaxPrefilter( function( s ) { + var i; + for ( i in s.headers ) { + if ( i.toLowerCase() === "content-type" ) { + s.contentType = s.headers[ i ] || ""; + } + } +} ); + + +jQuery._evalUrl = function( url, options, doc ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + + // Only evaluate the response if it is successful (gh-4126) + // dataFilter is not invoked for failure responses, so using it instead + // of the default converter is kludgy but it works. + converters: { + "text script": function() {} + }, + dataFilter: function( response ) { + jQuery.globalEval( response, options, doc ); + } + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var htmlIsFunction = isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.ontimeout = + xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain or forced-by-attrs requests + if ( s.crossDomain || s.scriptAttrs ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + + + + Contact — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Contact

+ +
+
+

Community Meeting

+

Talk to us and see what we’re working on at our monthly community meeting.

+
    +
  • Meeting minutes are here.

  • +
  • Recorded videos are posted here.

  • +
  • Our current project road map is here.

  • +
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/dev/developer-guide.html b/dev/developer-guide.html new file mode 100644 index 0000000000..f397d62d45 --- /dev/null +++ b/dev/developer-guide.html @@ -0,0 +1,725 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cartography Developer Guide — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+ + +
+
+ +
+

Cartography Developer Guide

+
+

Testing

+

*If you’d like to test using Docker and Docker Compose, see here*

+
+

Running from source

+
    +
  1. Install

    +
    +

    Follow steps 1 and 2 in Installation. Ensure that you have JVM 11 installed and Neo4j Community Edition 4.4 is running on your local machine.

    +
    +
  2. +
  3. Clone the source code

    +
    +

    Run cd {path-where-you-want-your-source-code}. Get the source code with git clone git://github.com/lyft/cartography.git

    +
    +
  4. +
  5. Install from source

    +
    +

    Run cd cartography and then pip install -e . (yes, actually type the period into the command line) to install Cartography from source.

    +

    ℹ️You may find it beneficial to use Python virtualenvs (or the virutalenvwrapper) so that packages installed via pip are easier to manage.

    +
    +
  6. +
  7. Run from source

    +
    +

    After this finishes you should be able to run Cartography from source with cartography --neo4j-uri <uri for your neo4j instance; usually bolt://localhost:7687>. Any changes to the source code in {path-where-you-want-your-source-code}/cartography are now locally testable by running cartography from the command line.

    +
    +
  8. +
+
+
+

Manually testing individual intel modules

+

After completing the section above, you are now able to manually test intel modules.

+
    +
  1. If needed, comment out unnecessary lines

    +
    +

    See cartography.intel.aws._sync_one_account()here. This function syncs different AWS objects with your Neo4j instance. Comment out the lines that you don’t want to test for.

    +

    For example, IAM can take a long time to ingest so if you’re testing an intel module that doesn’t require IAM nodes to already exist in the graph, then you can comment out all of the iam.sync_* lines.

    +
    +
  2. +
  3. Save your changes and run cartography from a terminal as you normally would.

  4. +
+
+
+

Automated testing

+
    +
  1. Install test requirements

    +
    +

    pip install -r test-requirements.txt

    +
    +
  2. +
  3. (OPTIONAL) Setup environment variables for integration tests

    +
    +

    The integration tests expect Neo4j to be running locally, listening on default ports, with auth disabled:

    +

    To disable auth, edit your neo4j.conf file with dbms.security.auth_enabled=false. Additional details on neo4j.com.

    +

    To run the integration tests on a specific Neo4j instance, add the following environment variable:

    +

    export "NEO4J_URL=<your_neo4j_instance_bolt_url:your_neo4j_instance_port>"

    +
    +
  4. +
  5. **Run tests using make**

    +
      +
    • make test_lint can be used to run pre-commit linting against the codebase. We use pre-commit to standardize our linting across our code-base at Lyft.

    • +
    • make test_unit can be used to run the unit test suite.

      +

      ⚠️ Important! The below commands will DELETE ALL NODES on your local Neo4j instance as part of our testing procedure. Only run any of the below commands if you are ok with this. ⚠️

      +
    • +
    • make test_integration can be used to run the integration test suite. +For more granular testing, you can invoke pytest directly:

      +
        +
      • pytest ./tests/integration/cartography/intel/aws/test_iam.py

      • +
      • pytest ./tests/integration/cartography/intel/aws/test_iam.py::test_load_groups

      • +
      +
    • +
    • make test can be used to run all of the above.

    • +
    +
  6. +
+
+
+
+

Implementing custom sync commands

+

By default, cartography will try to sync every intel module included as part of the default sync. If you’re not using certain intel modules you can create a custom sync script and invoke it using the cartography CLI. For example, if you’re only interested in the AWS intel module you can create a sync script, custom_sync.py, that looks like this:

+
from cartography import cli
+from cartography import sync
+from cartography.intel import aws
+from cartography.intel import create_indexes
+
+def build_custom_sync():
+    s = sync.Sync()
+    s.add_stages([
+        ('create-indexes', create_indexes.run),
+        ('aws', aws.start_aws_ingestion),
+    ])
+    return s
+
+def main(argv):
+    return cli.CLI(build_custom_sync(), prog='cartography').main(argv)
+
+if __name__ == '__main__':
+    import sys
+    sys.exit(main(sys.argv[1:]))
+
+
+

Which can then be invoked using python custom_sync.py and will have all the features of the cartography CLI while only including the intel modules you are specifically interested in using. For example:

+
cartography$ python custom_sync.py
+INFO:cartography.sync:Starting sync with update tag '1569022981'
+INFO:cartography.sync:Starting sync stage 'create-indexes'
+INFO:cartography.intel.create_indexes:Creating indexes for cartography node types.
+INFO:cartography.sync:Finishing sync stage 'create-indexes'
+INFO:cartography.sync:Starting sync stage 'aws'
+INFO:botocore.credentials:Found credentials in shared credentials file: ~/.aws/credentials
+...
+
+
+
+
+

How to write a new intel module

+

See here.

+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/dev/index.html b/dev/index.html new file mode 100644 index 0000000000..c36175e15f --- /dev/null +++ b/dev/index.html @@ -0,0 +1,619 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <no title> — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ + +
+
+
+ + + + + \ No newline at end of file diff --git a/dev/testing-with-docker.html b/dev/testing-with-docker.html new file mode 100644 index 0000000000..bd63adb61f --- /dev/null +++ b/dev/testing-with-docker.html @@ -0,0 +1,639 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Testing with docker — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Testing with docker

+
+

Using the included docker-compose support

+
+

Usage

+
docker build -t lyft/cartography
+docker-compose up -d
+docker-compose run cartography ...
+
+
+
+
+

Configuration

+

Configuration is possible via the .compose directory, which is +git ignored. neo4j config, logs, etc is located at .compose/neo4j/...

+

Configuration for cartography itself should be passed in through +environment variables, using the docker-compose format -e VARIABLE -e VARIABLE

+

AWS credentials can be bind mapped in using volumes. TODO: document correct +bind mount format for docker-compose run.

+
+
+

Notes

+
    +
  • On initial start of the compose stack, it’s necessary to +change the neo4j user’s password through the neo4j UI.

  • +
  • Neither the docker image, nor the docker-compose file define an +entrypoint, so it’s necessary to pass in the command being run. This +also makes it possible to run a custom sync script, rather than only +cartography.

  • +
+
+
+

Example

+
# Temporarily disable bash command history
+set +o history
+# See the cartography github configuration intel module docs
+export GITHUB_KEY=BASE64ENCODEDKEY
+# You need to set this after starting neo4j once, and resetting
+# the default neo4j password, which is neo4j
+export NEO4j_PASSWORD=...
+# Reenable bash command history
+set -o history
+# Start cartography dependencies
+docker-compose up -d
+# Run cartography
+docker-compose run -e GITHUB_KEY -e NEO4j_PASSWORD cartography cartography --github-config-env-var GITHUB_KEY --neo4j-uri bolt://neo4j:7687 --neo4j-password-env-var NEO4j_PASSWORD --neo4j-user neo4j
+
+
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/dev/writing-analysis-jobs.html b/dev/writing-analysis-jobs.html new file mode 100644 index 0000000000..8b095f6cd4 --- /dev/null +++ b/dev/writing-analysis-jobs.html @@ -0,0 +1,756 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + How to extend Cartography with Analysis Jobs — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+ + +
+
+ +
+

How to extend Cartography with Analysis Jobs

+
+

Overview

+

In a nutshell, Analysis Jobs let you add your own customizations to Cartography by writing Neo4j queries. This helps you add powerful enhancements to your data without the need to write Python code.

+
+

The stages

+

There are 3 stages to a cartography sync. First we create database indexes, next we ingest assets via intel modules, and finally we can run Analysis Jobs on the database (see cartography.sync.build_default_sync()). This tutorial focuses on Analysis Jobs.

+
+
+

How to run

+

Each Analysis Job is a JSON file with a list of Neo4j statements which get run in order. To run Analysis Jobs, in your call to cartography, set the --analysis-job-directory parameter to the folder path of your jobs. Although the order of statements within a single job is preserved, we don’t guarantee the order in which jobs are executed.

+
+
+
+

Example job: which of my EC2 instances is accessible to any host on the internet?

+

The easiest way to learn how to write an Analysis Job is through an example. One of the Analysis Jobs that we’ve included by default in Cartography’s source tree is cartography/data/jobs/analysis/aws_ec2_asset_exposure.json. This tutorial covers only the EC2 instance part of that job, but after reading this you should be able to understand the other steps in that file.

+
+

Our goal

+

After ingesting all our AWS data, we want to explicitly mark EC2 instances that are accessible to the public internet - a useful thing to know for anyone running an internet service. If any internet-open nodes are found, the job will add an attribute exposed_internet = True to the node. This way we can easily query to find the assets later on and take remediation action if needed.

+

But how do we make this determination, and how should we structure the job?

+
+
+

The logic in plain English

+

We can use the following facts to tell if an EC2 instance is open to the internet:

+
    +
  1. The EC2 instance is a member of a Security Group that has an IP Rule applied to it that allows inbound traffic from the 0.0.0.0/0 subnet.

  2. +
  3. The EC2 instance has a network interface that is connected to a Security Group that has an IP Rule applied to it that allows inbound traffic from the 0.0.0.0/0 subnet.

  4. +
+

The graph created by Cartography’s sync process already has this information for us; we just need to run a few queries to properly to mark it with exposed_internet = True. This example is complex but we hope that this exposes enough Neo4j concepts to help you write your own queries.

+
+
+

Translating the plain-English logic into Neo4j’s Cypher syntax

+

We can take the ideas above and use Cypher’s declarative syntax to “sketch” out this graph path.

+
    +
  1. The EC2 instance is a member of a Security Group that has an IP Rule applied to it that allows inbound traffic from the 0.0.0.0/0 subnet.

    +
    +

    In Cypher, this is

    +
    +
       MATCH
    +   (:IpRange{id: '0.0.0.0/0'})-[:MEMBER_OF_IP_RULE]->(:IpPermissionInbound)
    +   -[:MEMBER_OF_EC2_SECURITY_GROUP]->(group:EC2SecurityGroup)
    +   <-[:MEMBER_OF_EC2_SECURITY_GROUP]-(instance:EC2Instance)
    +
    +   SET instance.exposed_internet = true,
    +       instance.exposed_internet_type = coalesce(instance.exposed_internet_type , []) + 'direct';
    +
    +In the ``SET`` clause we add ``exposed_internet = True`` to the instance. We also add a field for ``exposed_internet_type`` to denote what type of internet exposure has occurred here. You can read the `documentation for ``coalesce`` <https://neo4j.com/docs/cypher-manual/current/functions/scalar/#functions-coalesce>`_\ , but in English this last part says "add ``direct`` to the list of ways this instance is exposed to the internet".
    +
    +
    +
  2. +
  3. The EC2 instance has a network interface that is connected to a Security Group that has an IP Rule applied to it that allows inbound traffic from the 0.0.0.0/0 subnet.

    +
    +

    This is the same as the previous query except for the final line:

    +
    +
       MATCH
    +   (:IpRange{id: '0.0.0.0/0'})-[:MEMBER_OF_IP_RULE]->(:IpPermissionInbound)
    +   -[:MEMBER_OF_EC2_SECURITY_GROUP]->(group:EC2SecurityGroup)
    +   <-[:NETWORK_INTERFACE*..2]-(instance:EC2Instance)
    +
    +   SET instance.exposed_internet = true,
    +       instance.exposed_internet_type = coalesce(instance.exposed_internet_type , []) + 'direct';
    +
    +The ``*..2`` operator means "within 2 hops". We use this here as a shortcut because there are a few more relationships between NetworkInterfaces and EC2SecurityGroups that we can skip over.
    +
    +
    +
  4. +
+

Finally, notice that (1) and (2) are similar enough that we can actually merge them like this:

+
MATCH
+(:IpRange{id: '0.0.0.0/0'})-[:MEMBER_OF_IP_RULE]->(:IpPermissionInbound)
+-[:MEMBER_OF_EC2_SECURITY_GROUP]->(group:EC2SecurityGroup)
+<-[:MEMBER_OF_EC2_SECURITY_GROUP|NETWORK_INTERFACE*..2]-(instance:EC2Instance)
+
+SET instance.exposed_internet = true,
+    instance.exposed_internet_type = coalesce(instance.exposed_internet_type , []) + 'direct';
+
+
+

Kinda neat, right?

+
+
+

The skeleton of an Analysis Job

+

Now that we know what we want to do on a sync, how should we structure the Analysis Job? Here is the basic skeleton that we recommend.

+
+

Clean up first, then update

+

In general, the first statement(s) should be a “clean-up phase” that removes custom attributes or relationships that you may have added in a previous run. This ensures that whatever labels you add on this current run will be up to date and not stale. Next, the statements after the clean-up phase will perform the matching and attribute updates as described in the previous section.

+

Here’s our final result:

+
{
+  "name": "AWS asset internet exposure",
+  "statements": [
+      {
+        "__comment": "This is a clean-up statement to remove custom attributes",
+        "query": "MATCH (n)
+                  WHERE n.exposed_internet IS NOT NULL
+                        AND labels(n) IN ['AutoScalingGroup', 'EC2Instance', 'LoadBalancer']
+                  WITH n LIMIT $LIMIT_SIZE
+                  REMOVE n.exposed_internet, n.exposed_internet_type
+                  RETURN COUNT(*) as TotalCompleted",
+        "iterative": true,
+        "iterationsize": 1000
+      },
+      {
+        "__comment__": "This is our analysis logic as described in the section above",
+        "query": MATCH (:IpRange{id: '0.0.0.0/0'})-[:MEMBER_OF_IP_RULE]->(:IpPermissionInbound)
+                 -[:MEMBER_OF_EC2_SECURITY_GROUP]->(group:EC2SecurityGroup)
+                 <-[:MEMBER_OF_EC2_SECURITY_GROUP|NETWORK_INTERFACE*..2]-(instance:EC2Instance)
+
+                 SET instance.exposed_internet = true,
+                     instance.exposed_internet_type = coalesce(instance.exposed_internet_type , []) + 'direct';,
+        "iterative": true,
+        "iterationsize": 100
+      }
+  ]
+}
+
+
+

Setting a statement as iterative: true means that we will run this query on #{iterationsize} entries at a time. This can be helpful for queries that return large numbers of records so that Neo4j doesn’t get too angry.

+

Now we can enjoy the fruits of our labor and query for internet exposure:

+internet-exposure-query +
+
+
+
+

Recap

+

As shown, you create an Analysis Job by putting together a bunch of statements together (which are essentially Neo4j queries). In general, each job should first clean up the custom attributes added by a previous run, and then it can perform the match and update steps to add the custom attributes back again. This ensures that your data is up to date.

+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/dev/writing-intel-modules.html b/dev/writing-intel-modules.html new file mode 100644 index 0000000000..04ba22c765 --- /dev/null +++ b/dev/writing-intel-modules.html @@ -0,0 +1,1075 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + How to write a new intel module — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+ + +
+
+ +
+

How to write a new intel module

+

If you want to add a new data type to Cartography, this is the guide for you. We look forward to receiving your PR!

+
+

Before getting started…

+

Read through and follow the setup steps in the Cartography developer guide. Learn the basics of +running, testing, and linting your code there.

+
+
+

The fast way

+

To get started coding without reading this doc, just copy the structure of our AWS EMR module and use it as an example. For a longer written explanation of the “how” and “why”, read on.

+
+
+

Configuration and credential management

+
+

Supplying credentials and arguments to your module

+

If you need to supply an API key or other credential to your Cartography module, we recommend adding a CLI argument. An example of this can be seen in our Okta module where we require the user to specify the name of an environment variable containing their Okta API key. This credential will then be bound to Cartography’s Config object which is present in all modules. You can specify different arguments from the commandline for your module via the Config object.

+
+
+

An important note on validating your commandline args

+

Note that it is your module’s responsibility to validate arguments that you introduce. For example with the Okta module, we validate that config.okta_api_key has been defined before attempting to continue.

+
+
+
+

Sync = Get, Transform, Load, Cleanup

+

A cartography intel module consists of one sync function. sync should call get, then load, and finally cleanup.

+
+

Get

+

The get function returns data as a list of dicts +from a resource provider API, which is GCP in this particular example.

+

get should be “dumb” in the sense that it should not handle retry logic or data +manipulation. It should also raise an exception if it’s not able to complete successfully.

+
+
+

Transform

+

The transform function manipulates the list of dicts +to make it easier to ingest to the graph. transform functions are sometimes omitted when a module author decides that the output from the get is already in the shape that they need.

+

We have some best practices on handling transforms:

+
+

Handling required versus optional fields

+

We should directly access dicts in cases where not having the data should cause a sync to fail. +For example, if we are transforming AWS data, we definitely need an AWS object’s ARN field because it uniquely +identifies the object. Therefore, we should access an object’s ARN using data['arn'] as opposed to +using data.get('arn') (the former will raise a KeyError if arn does not exist and the latter will just return +None without an exception).

+

We want the sync to fail if an important field is not present in our data. The idea here is that +it is better to fail a sync than to add malformed data.

+

On the other hand, we should use data.get('SomeField') if SomeField is something optional that can afford to be +None.

+

For the sake of consistency, if a field does not exist, set it to None and not "".

+
+
+
+

Load

+

As seen in our AWS EMR example, the load function ingests a list of dicts to Neo4j by calling cartography.client.core.tx.load():

+
def load_emr_clusters(
+        neo4j_session: neo4j.Session,
+        cluster_data: List[Dict[str, Any]],
+        region: str,
+        current_aws_account_id: str,
+        aws_update_tag: int,
+) -> None:
+    logger.info(f"Loading EMR {len(cluster_data)} clusters for region '{region}' into graph.")
+    load(
+        neo4j_session,
+        EMRClusterSchema(),
+        cluster_data,
+        lastupdated=aws_update_tag,
+        Region=region,
+        AWS_ID=current_aws_account_id,
+    )
+
+
+
+

Defining a node

+

As an example of a CartographyNodeSchema, you can view our EMRClusterSchema code:

+
@dataclass(frozen=True)
+class EMRClusterSchema(CartographyNodeSchema):
+    label: str = 'EMRCluster'  # The label of the node
+    properties: EMRClusterNodeProperties = EMRClusterNodeProperties()  # An object representing all properties on the EMR Cluster node
+    sub_resource_relationship: EMRClusterToAWSAccount = EMRClusterToAWSAccount()
+
+
+

An EMRClusterSchema object inherits from the CartographyNodeSchema class and contains a node label, properties, and connection to its sub-resource: an AWSAccount.

+

Note that the typehints are necessary for Python dataclasses to work properly.

+
+
+

Defining node properties

+

Here’s our EMRClusterNodeProperties code:

+
@dataclass(frozen=True)
+class EMRClusterNodeProperties(CartographyNodeProperties):
+    arn: PropertyRef = PropertyRef('ClusterArn', extra_index=True)
+    firstseen: PropertyRef = PropertyRef('firstseen')
+    id: PropertyRef = PropertyRef('Id')
+    # ...
+    lastupdated: PropertyRef = PropertyRef('lastupdated', set_in_kwargs=True)
+    region: PropertyRef = PropertyRef('Region', set_in_kwargs=True)
+    security_configuration: PropertyRef = PropertyRef('SecurityConfiguration')
+
+
+

A CartographyNodeProperties object consists of ``PropertyRef` <https://github.com/lyft/cartography/blob/e6ada9a1a741b83a34c1c3207515a1863debeeb9/cartography/graph/model.py#L37>`_ objects. PropertyRefs tell querybuilder.build_ingestion_query() where to find appropriate values for each field from the list of dicts.

+

For example, id: PropertyRef = PropertyRef('Id') above tells the querybuilder to set a field called id on the EMRCluster node using the value located at key 'id' on each dict in the list.

+

As another example, region: PropertyRef = PropertyRef('Region', set_in_kwargs=True) tells the querybuilder to set a field called region on the EMRCluster node using a keyword argument called Region supplied to cartography.client.core.tx.load(). set_in_kwargs=True is useful in cases where we want every object loaded by a single call to load() to have the same value for a given attribute.

+
+
Node property indexes
+

Cartography uses its data model to automatically create indexes for

+
    +
  • node properties that uniquely identify the node (e.g. id)

  • +
  • node properties are used to connect a node to other nodes (i.e. they are used as part of a TargetNodeMatcher on a CartographyRelSchema.)

  • +
  • a node’s lastupdated field – this is used to enable faster cleanup jobs

  • +
+

As seen in the above definition for EMRClusterNodeProperties.arn, you can also explicitly specify additional indexes for fields that you expect to be queried on by providing extra_index=True to the PropertyRef constructor:

+
class EMRClusterNodeProperties(CartographyNodeProperties):
+    # ...
+    arn: PropertyRef = PropertyRef('ClusterArn', extra_index=True)
+
+
+

Index creation is idempotent (we only create them if they don’t exist).

+

See below for more information on indexes.

+
+
+
+

Defining relationships

+

Relationships can be defined on CartographyNodeSchema on either their ``sub_resource_relationship` <https://github.com/lyft/cartography/blob/e6ada9a1a741b83a34c1c3207515a1863debeeb9/cartography/graph/model.py#L216-L228>`_ field or their ``other_relationships` <https://github.com/lyft/cartography/blob/e6ada9a1a741b83a34c1c3207515a1863debeeb9/cartography/graph/model.py#L230-L237>`_ field (you can find an example of other_relationships here in our test data).

+

As seen above, an EMRClusterSchema only has a single relationship defined: an ``EMRClusterToAWSAccount` <https://github.com/lyft/cartography/blob/e6ada9a1a741b83a34c1c3207515a1863debeeb9/cartography/intel/aws/emr.py#L94-L103>`_:

+
@dataclass(frozen=True)
+# (:EMRCluster)<-[:RESOURCE]-(:AWSAccount)
+class EMRClusterToAWSAccount(CartographyRelSchema):
+    target_node_label: str = 'AWSAccount'  # (1)
+    target_node_matcher: TargetNodeMatcher = make_target_node_matcher(  # (2)
+        {'id': PropertyRef('AccountId', set_in_kwargs=True)},
+    )
+    direction: LinkDirection = LinkDirection.INWARD  # (3)
+    rel_label: str = "RESOURCE"  # (4)
+    properties: EMRClusterToAwsAccountRelProperties = EMRClusterToAwsAccountRelProperties()  #  (5)
+
+
+

This class is best described by explaining how it is processed: build_ingestion_query() will traverse the EMRClusterSchema to its sub_resource_relationship field and find the above EMRClusterToAWSAccount object. With this information, we know to

+
    +
  • draw a relationship to an AWSAccount node (1) using the label “RESOURCE” (4)

  • +
  • by matching on the AWSAccount’s “id” field” (2)

  • +
  • where the relationship directionality is pointed inward toward the EMRCluster (3)

  • +
  • making sure to define a set of properties for the relationship (5). The full example RelProperties is very short:

  • +
+
@dataclass(frozen=True)
+class EMRClusterToAwsAccountRelProperties(CartographyRelProperties):
+    lastupdated: PropertyRef = PropertyRef('lastupdated', set_in_kwargs=True)
+
+
+
+
+

The result

+

And those are all the objects necessary for this example! The resulting query will look something like this:

+
UNWIND $DictList AS item
+    MERGE (i:EMRCluster{id: item.Id})
+    ON CREATE SET i.firstseen = timestamp()
+    SET
+        i.lastupdated = $lastupdated,
+        i.arn = item.ClusterArn
+        // ...
+
+        WITH i, item
+        CALL {
+            WITH i, item
+
+            OPTIONAL MATCH (j:AWSAccount{id: $AccountId})
+            WITH i, item, j WHERE j IS NOT NULL
+            MERGE (i)<-[r:RESOURCE]-(j)
+            ON CREATE SET r.firstseen = timestamp()
+            SET
+                r.lastupdated = $lastupdated
+        }
+
+
+

And that’s basically all you need to know to understand how to define your own nodes and relationships using cartography’s data objects. For more information, you can view the object model API documentation as a reference.

+
+
+
+

Additional concepts

+

This section explains cartography general patterns, conventions, and design decisions.

+
+

cartography’s update_tag:

+

cartography‘s global config object carries around an ``update_tag` property <https://github.com/lyft/cartography/blob/8d60311a10156cd8aa16de7e1fe3e109cc3eca0f/cartography/cli.py#L91-L98>`_ +which is a tag/label associated with the current sync. +Cartography’s CLI code sets this to a Unix timestamp of when the CLI was run.

+

All cartography intel modules set the lastupdated property on all nodes and all relationships to this update_tag.

+
+
+

All nodes need these fields

+
    +
  • +
    `id` - an ID should be a string that uniquely identifies the node. In AWS, this is usually an

    ARN. In GCP, this is usually a partial URI.

    +

    If possible, we should use API-provided fields for IDs and not create our own. +In some cases though this is unavoidable - +see GCPNetworkTag.

    +

    When setting an id, ensure that you also include the field name that it came from. For example, since we’ve +decided to use partial_uris as an id for a GCPVpc, we should include both partial_uri and id on the node. +This way, a user can tell what fields were used to derive the id. This is accomplished here

    +
    +
    +
  • +
  • lastupdated - See below on how this gets set automatically.

  • +
  • firstseen - See below on how this gets set automatically.

  • +
+
+
+

All relationships need these fields

+

Cartography currently does not create indexes on relationships, so in most cases we should keep relationships lightweight with only these two fields:

+
    +
  • lastupdated - See below on how this gets set automatically.

  • +
  • firstseen - See below on how this gets set automatically.

  • +
+
+
+

Run queries only on indexed fields for best performance

+

In this older example of ingesting GCP VPCs, we connect VPCs with GCPProjects +based on GCPProject ``id`s and GCPVpc ids <https://github.com/lyft/cartography/blob/8d60311a10156cd8aa16de7e1fe3e109cc3eca0f/cartography/intel/gcp/compute.py#L451>`_. +ids are indexed, as seen here +and here. +All of these queries use indexes for faster lookup.

+
+
+

indexes.cypher

+

Older intel modules define indexes in indexes.cypher. +By using CartographyNodeSchema and CartographyRelSchema objects, indexes are automatically created so you don’t need to update this file!

+
+
+

lastupdated and firstseen

+

On every cartography node and relationship, we set the lastupdated field to the UPDATE_TAG and firstseen field to timestamp() (a built-in Neo4j function equivalent to epoch time in milliseconds). This is automatically handled by the cartography object model.

+
+
+
+

Cleanup

+

We have just added new nodes and relationships to the graph, and we have also updated previously-added ones +by using MERGE. We now need to delete nodes and relationships that no longer exist, and we do this by removing +all nodes and relationships that have lastupdated NOT set to the update_tag of this current run.

+

By using Cartography schema objects, a cleanup function is trivial to write:

+
def cleanup(neo4j_session: neo4j.Session, common_job_parameters: Dict) -> None:
+    logger.debug("Running EMR cleanup job.")
+    cleanup_job = GraphJob.from_node_schema(EMRClusterSchema(), common_job_parameters)
+    cleanup_job.run(neo4j_session)
+
+
+

Older intel modules still do this process with hand-written cleanup jobs that work like this:

+
    +
  • Delete all old nodes

    +
    +

    You can see this in our GCP VPCs example. +We run DETACH DELETE to delete an old node and disconnect it from all other nodes.

    +
    +
      +
    • Delete all old relationships

      +

      You can see this in the GCP VPC example here +and here.

      +
        +
      • Q: We just DETACH DELETE‘d the node. Why do we need to delete the relationships too?

      • +
      • +
        A: There are cases where the node may continue to exist but the relationships between it and other nodes have changed.

        Explicitly deleting stale relationships accounts for this case. +See this short discussion.

        +
        +
        +
      • +
      +
    • +
    +
  • +
+
+
+
+

Error handling principles

+
    +
  • Don’t catch the base Exception class when error handling because it makes problems difficult to trace.

  • +
  • Do catch the narrowest possible class of exception.

  • +
  • Only catch exceptions when your code can resolve the issue. Otherwise, allow exceptions to bubble up.

  • +
+
+
+

Schema

+
    +
  • Update the schema +with every change!

  • +
+
+
+

Making tests

+ +
+
+

Other

+
    +
  • We prefer and will accept PRs which incrementally add information from a particular data source. Incomplete +representations are OK provided they are consistent over time. For example, we don’t sync 100% of AWS resources but the +resources that exist in the graph don’t change across syncs.

  • +
  • Each intel module offers its own view of the graph

    +
    +

    ℹ️ This best practice is a little more less precise, so if you’ve gotten to this point and you need clarification, just +submit your PR and ask us.

    +

    As much as possible, each intel module should ingest data without assuming that a different module will ingest the +same data. Explained another way, each module should “offer its own perspective” on the data. We believe doing this +gives us a more complete graph. Below are some key guidelines clarifying and justifying this design choice.

    +
    +
      +
    • Use MERGE when connecting one node type to another node type.

    • +
    • It is possible (and encouraged) for more than one intel module to modify the same node type.

      +
      +

      For example, when we connect RDS instances to their associated EC2 security +groups +there are actually two different intel modules that retrieve EC2 security group data: the RDS module +returns partial group data, +and the EC2 module returns more complete data as it calls APIs specific for retrieving and loading security groups. +Because both the RDS and EC2 modules MERGE on a unique ID, we don’t need to worry about +creating duplicate nodes in the graph.

      +

      Another less obvious benefit of using MERGE across more than one intel module to connect nodes in this way is that +in many cases, we’ve seen an intel module discover nodes that another module was not aware of!

      +
      +
    • +
    +
  • +
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000000..157d78590d --- /dev/null +++ b/index.html @@ -0,0 +1,547 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + What is Cartography? — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ + logo +
+

What is Cartography?

+

Cartography is a Python tool that consolidates infrastructure assets and the relationships between them in an intuitive graph view powered by a Neo4j database.

+example +
+
+

Why Cartography?

+

Cartography aims to enable a broad set of exploration and automation scenarios. It is particularly good at exposing otherwise hidden dependency relationships between your service’s assets so that you may validate assumptions about security risks.

+

Service owners can generate asset reports, Red Teamers can discover attack paths, and Blue Teamers can identify areas for security improvement. All can benefit from using the graph for manual exploration through a web frontend interface, or in an automated fashion by calling the APIs.

+

Cartography is not the only security graph tool out there, but it differentiates itself by being fully-featured yet generic and extensible enough to help make anyone better understand their risk exposure, regardless of what platforms they use. Rather than being focused on one core scenario or attack vector like the other linked tools, Cartography focuses on flexibility and exploration.

+

You can learn more about the story behind Cartography in our presentation at BSidesSF 2019.

+
+
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/info.html b/info.html new file mode 100644 index 0000000000..ce12b2bf5a --- /dev/null +++ b/info.html @@ -0,0 +1,568 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + What is Cartography? — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ + logo +
+

What is Cartography?

+

Cartography is a Python tool that consolidates infrastructure assets and the relationships between them in an intuitive graph view powered by a Neo4j database.

+example +
+
+

Why Cartography?

+

Cartography aims to enable a broad set of exploration and automation scenarios. It is particularly good at exposing otherwise hidden dependency relationships between your service’s assets so that you may validate assumptions about security risks.

+

Service owners can generate asset reports, Red Teamers can discover attack paths, and Blue Teamers can identify areas for security improvement. All can benefit from using the graph for manual exploration through a web frontend interface, or in an automated fashion by calling the APIs.

+

Cartography is not the only security graph tool out there, but it differentiates itself by being fully-featured yet generic and extensible enough to help make anyone better understand their risk exposure, regardless of what platforms they use. Rather than being focused on one core scenario or attack vector like the other linked tools, Cartography focuses on flexibility and exploration.

+

You can learn more about the story behind Cartography in our presentation at BSidesSF 2019.

+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/install.html b/install.html new file mode 100644 index 0000000000..d49f9f5114 --- /dev/null +++ b/install.html @@ -0,0 +1,607 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cartography Installation — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Cartography Installation

+

Time to set up the server that will run Cartography. Cartography should work on both Linux and Windows servers, but bear in mind we’ve only tested it in Linux so far. Cartography supports Python 3.8. Older versions of Python may work but are not explicitly supported.

+
    +
  1. Run the Neo4j graph database version 4.x on your server.

    +
    ⚠️ Neo4j 5.x will probably work but Cartography does not explicitly support it yet.
    +
    +
    +
      +
    1. If you prefer Docker, follow the Neo4j Docker official docs to run a version 4.x container.

      +
        +
      • If you are using an ARM-based machine like an M1 Mac, you should use an ARM image otherwise performance will be very slow - Neo4j keeps ARM builds here.

      • +
      • If you’re just playing around, you can specify the --env=NEO4J_AUTH=none argument to your docker command to run a Neo4j container without authentication.

      • +
      +
    2. +
    3. Else if you prefer a manual install,

      +
        +
      1. Neo4j requires a JVM (JDK/JRE 11 or higher) to be installed. One option is to install Amazon Coretto 11.

        +
        ⚠️ Make sure you have `JAVA_HOME` environment variable set. The following works for Mac OS: `export JAVA_HOME=$(/usr/libexec/java_home)`
        +
        +
        +
      2. +
      3. Go to the Neo4j download page, and download Neo4j Community Edition 4.4.*. If you prefer Docker, you can view Neo4j’s instructions [here].

      4. +
      5. Install Neo4j on the server you will run Cartography on.

        +
        ⚠️ For local testing, you might want to turn off authentication via property `dbms.security.auth_enabled` in file /NEO4J_PATH/conf/neo4j.conf
        +
        +
        +
      6. +
      +
    4. +
    +
  2. +
  3. Configure your data sources. See the configuration section of each relevant intel module for more details.

  4. +
  5. Get and run Cartography

    +
      +
    1. Run pip install cartography to install our code.

    2. +
    3. Finally, to sync your data:

      +
        +
      • For one account using the default profile defined in your AWS config file, run

        +
        cartography --neo4j-uri <uri for your neo4j instance; usually bolt://localhost:7687>
        +
        +
        +
      • +
      • Or for a specific account defined as a separate profile in your AWS config file, set the AWS_PROFILE environment variable, for example

        +
        AWS_PROFILE=other-profile cartography --neo4j-uri <uri for your neo4j instance; usually bolt://localhost:7687>
        +
        +
        +
      • +
      • For more than one AWS account, run

        +
        AWS_CONFIG_FILE=/path/to/your/aws/config cartography --neo4j-uri <uri for your neo4j instance; usually bolt://localhost:7687> --aws-sync-all-profiles
        +
        +
        +

        You can view a full list of Cartography’s CLI arguments by running cartography --help

        +

        The sync will pull data from your configured accounts and ingest data to Neo4j! This process might take a long time if your account has a lot of assets.

        +
      • +
      +
    4. +
    5. See our Operations Guide for tips on running Cartography in production.

    6. +
    +
  6. +
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/_cartography-metadata/schema.html b/modules/_cartography-metadata/schema.html new file mode 100644 index 0000000000..e691b18b4c --- /dev/null +++ b/modules/_cartography-metadata/schema.html @@ -0,0 +1,555 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cartography metadata schema — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Cartography metadata schema

+

Some Cartography sync jobs write nodes to convey information about the job itself. See https://github.com/lyft/cartography/issues/758 for more background on this.

+
+

SyncMetadata:ModuleSyncMetadata

+

This is a node to represent metadata about the sync job of a particular module. Its existence indicates that a particular sync job did happen. +The ‘types’ used here should be actual node labels. For example, if we did sync a particular AWSAccount’s S3Buckets, +the grouptype is ‘AWSAccount’, the groupid is the particular account’s id, and the syncedtype is ‘S3Bucket’.

+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

Source

id

{group_type}_{group_id}_{synced_type}

util.py

grouptype

The parent module’s type

util.py

groupid

The parent module’s id

util.py

syncedtype

The sub-module’s type

util.py

+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/aws/config.html b/modules/aws/config.html new file mode 100644 index 0000000000..7ddd7a44f4 --- /dev/null +++ b/modules/aws/config.html @@ -0,0 +1,685 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AWS Configuration — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

AWS Configuration

+

Follow these steps to analyze AWS assets with Cartography.

+
+

Single AWS Account Setup

+
    +
  1. Set up an AWS identity (user, group, or role) for Cartography to use. Ensure that this identity has the built-in AWS SecurityAudit policy (arn:aws:iam::aws:policy/SecurityAudit) attached. This policy grants access to read security config metadata. The SecurityAudit policy does not yet containe permissions for inspector2, so you will also need the AmazonInspector2ReadOnlyAccess policy.

  2. +
  3. Set up AWS credentials to this identity on your server, using a config and credential file. For details, see AWS’ official guide.

  4. +
  5. [Optional] Configure AWS Retry settings using AWS_MAX_ATTEMPTS and AWS_RETRY_MODE environment variables. This helps in API Rate Limit throttling and TooManyRequestException related errors. For details, see AWS’ official guide.

  6. +
+
+
+

Multiple AWS Account Setup

+

There are many ways to allow Cartography to pull from more than one AWS account. We can’t cover all of them, but we can show you the way we have things set up at Lyft. In this scenario we will assume that you are going to run Cartography on an EC2 instance.

+
    +
  1. Pick one of your AWS accounts to be the “Hub” account. This Hub account will pull data from all of your other accounts - we’ll call those “Spoke” accounts.

  2. +
  3. Set up the IAM roles: Create an IAM role named cartography-read-only on all of your accounts. Configure the role on all accounts as follows:

    +

    #. Attach the built-in AWS SecurityAudit IAM policy (arn:aws:iam::aws:policy/SecurityAudit) to the role. This grants access to read security config metadata. +#.

    +
    +

    Set up a trust relationship so that the Spoke accounts will allow the Hub account to assume the cartography-read-only role. The resulting trust relationship should look something like this:

    +
    {
    +  "Version": "2012-10-17",
    +  "Statement": [
    +    {
    +      "Effect": "Allow",
    +      "Principal": {
    +        "AWS": "arn:aws:iam::<Hub's account number>:root"
    +      },
    +      "Action": "sts:AssumeRole"
    +    }
    +  ]
    +}
    +
    +
    +
    +
      +
    1. Allow a role in the Hub account to assume the ``cartography-read-only`` role on your Spoke account(s).

      +
        +
      • On the Hub account, create a role called cartography-service.

      • +
      • On this new cartography-service role, add an inline policy with the following JSON:

        +
           {
        +     "Version": "2012-10-17",
        +     "Statement": [
        +       {
        +         "Effect": "Allow",
        +         "Resource": "arn:aws:iam::*:role/cartography-read-only",
        +         "Action": "sts:AssumeRole"
        +       },
        +       {
        +         "Effect": "Allow",
        +         "Action": "ec2:DescribeRegions",
        +         "Resource": "*"
        +       }
        +     ]
        +   }
        +
        +This allows the Hub role to assume the ``cartography-read-only`` role on your Spoke accounts and to fetch all the different regions used by the Spoke accounts.
        +
        +
        +
      • +
      • When prompted to name the policy, you can name it anything you want - perhaps CartographyAssumeRolePolicy.

      • +
      +
    2. +
    +
  4. +
  5. Set up your EC2 instance to correctly access these AWS identities

    +
      +
    1. Attach the cartography-service role to the EC2 instance that you will run Cartography on. You can do this by following these official AWS steps.

    2. +
    3. Ensure that the [default] profile in your AWS_CONFIG_FILE file (default ~/.aws/config in Linux, and %UserProfile%\.aws\config in Windows) looks like this:

      +
      [default]
      +region=<the region of your Hub account, e.g. us-east-1>
      +output=json
      +
      +
      +
    4. +
    5. Add a profile for each AWS account you want Cartography to sync with to your AWS_CONFIG_FILE. It will look something like this:

      +
      [profile accountname1]
      +role_arn = arn:aws:iam::<AccountId#1>:role/cartography-read-only
      +region=us-east-1
      +output=json
      +credential_source = Ec2InstanceMetadata
      +
      +[profile accountname2]
      +role_arn = arn:aws:iam::<AccountId#2>:role/cartography-read-only
      +region=us-west-1
      +output=json
      +credential_source = Ec2InstanceMetadata
      +
      +... etc ...
      +
      +
      +
    6. +
    +
  6. +
  7. [Optional] Configure AWS Retry settings using AWS_MAX_ATTEMPTS and AWS_RETRY_MODE environment variables. This helps in API Rate Limit throttling and TooManyRequestException related errors. For details, see AWS’ official guide.

  8. +
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/aws/index.html b/modules/aws/index.html new file mode 100644 index 0000000000..d892b598d6 --- /dev/null +++ b/modules/aws/index.html @@ -0,0 +1,593 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Amazon Web Services (AWS) — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Amazon Web Services (AWS)

+

The AWS module has the following coverage:

+
    +
  • API Gateway - Rest APIs, Stages, Certificates, Resources

  • +
  • Config - Configuration Recorders, Delivery Channels, Config Rules

  • +
  • EC2 - Autoscaling groups, Elastic IPs, AMIs, Instances, Internet Gateways, SSH Key Pairs, Launch Templates, Launch Config, Load Balancers (V1 and V2), Network Interfaces, Reserved Instances, Security Groups, EBS Volumes, EBS Snapshots, Subnets, Trusted Gateway, VPC, VPC Peerings

  • +
  • Elasticsearch - Domains

  • +
  • Elastic Kubernetes Service - Clusters

  • +
  • DynamoDB - Tables, Global Secondary Indexes

  • +
  • IAM - Users, User Access Keys, Roles, Groups, Group Membership, Principals, Policies (managed and inline), Assume Role Relationships

  • +
  • KMS - Keys, Key Policy, Grants, Aliases

  • +
  • Lambda - Functions, Aliases, Source Mappings, Layers

  • +
  • RDS - Clusters, Instances, Subnet Groups, Security Groups, Read Replicas

  • +
  • Redshift - Clusters

  • +
  • Route53 - Records, Zones

  • +
  • S3 - Buckets, Bucket Policy, ACLs

  • +
  • Secrets Manager - Secrets

  • +
  • Security Hub - Basic Hub Details

  • +
  • SQS - Queues, Dead Letter Queues

  • +
  • STS

  • +
  • Tags - Tag support for the supported resources, if supported by the resource groups tagging API

  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/aws/permissions-mapping.html b/modules/aws/permissions-mapping.html new file mode 100644 index 0000000000..b9a6e91350 --- /dev/null +++ b/modules/aws/permissions-mapping.html @@ -0,0 +1,626 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Permissions Mapping — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Permissions Mapping

+
+

How to use Permissions Mapping

+

An AWSPrincipal contains AWSPolicies which contain AWSPolicyStatements which grant permission to resources. Cartography can map in permission relationships between IAM Pricipals (AWSPrincipal nodes) and the resources they have permission to.

+

As mapping all permissions is infeasible both to calculate and store Cartography will only map in the relationships defined in the permission relationship file which includes some default permission mappings including s3 read access.

+

You can specify your own permission mapping file using the --permission-relationships-file command line parameter

+
+

Permission Mapping File

+

The permission relationship file is a yaml file that specifies what permission relationships should be created in the graph. It consists of RPR (Resource Permission Relationship) sections that are going to map specific permissions between AWSPrincipals and resources

+
- target_label: S3Bucket
+  permissions:
+  - S3:GetObject
+  relationship_name: CAN_READ
+
+
+

Each RPR consists of

+
    +
  • ResourceType (string) - The node Label that permissions will be built for

  • +
  • Permissions (list(string)) - The list of permissions to map. If any of these permissions are present between a resource and a permission then the relationship is created.

  • +
  • RelationshipName - (string) - The name of the relationship cartography will create

  • +
+

It can also be used to absract many different permissions into one. This example combines all of the permissions that would allow a dynamodb table to be queried.

+
- target_label: DynamoDBTable
+  permissions:
+  - dynamodb:BatchGetItem
+  - dynamodb:GetItem
+  - dynamodb:GetRecords
+  - dynamodb:Query
+  relationship_name: CAN_QUERY
+
+
+

If a principal has any of the permission it will be mapped

+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/aws/schema.html b/modules/aws/schema.html new file mode 100644 index 0000000000..a71e664d32 --- /dev/null +++ b/modules/aws/schema.html @@ -0,0 +1,8248 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AWS Schema — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

AWS Schema

+
+

AWSAccount

+

Representation of an AWS Account.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

name

The name of the account

inscope

Indicates that the account is part of the sync scope (true or false).

foreign

Indicates if the account is not part of the sync scope (true or false). One such example is an account that is trusted as part of cross-account AWSRole trust not in scope for sync.

lastupdated

Timestamp of the last time the node was updated

id

The AWS Account ID number

+
+

Relationships

+
    +
  • Many node types belong to an AWSAccount.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSDNSZone,
    +                      AWSGroup,
    +                      AWSInspectorFinding,
    +                      AWSInspectorPackage,
    +                      AWSLambda,
    +                      AWSPrincipal,
    +                      AWSUser,
    +                      AWSVpc,
    +                      AutoScalingGroup,
    +                      DNSZone,
    +                      DynamoDBTable,
    +                      EBSSnapshot,
    +                      EBSVolume,
    +                      EC2Image,
    +                      EC2Instance,
    +                      EC2Reservation,
    +                      EC2ReservedInstance,
    +                      EC2SecurityGroup,
    +                      ElasticIPAddress,
    +                      ESDomain,
    +                      LaunchConfiguration,
    +                      LaunchTemplate,
    +                      LaunchTemplateVersion,
    +                      LoadBalancer,
    +                      RDSCluster,
    +                      RDSInstance,
    +                      RDSSnapshot,
    +                      SecretsManagerSecret,
    +                      SecurityHub,
    +                      SQSQueue
    +                      SSMInstanceInformation,
    +                      SSMInstancePatch)
    +```
    +
    +
    +
  • +
  • An AWSPolicy node is defined for an AWSAccount.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSPolicy)
    +```
    +
    +
    +
  • +
  • AWSRole nodes are defined in AWSAccount nodes.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSRole)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSCidrBlock

+
+

AWSIpv4CidrBlock

+
+
+

AWSIpv6CidrBlock

+

Representation of an AWS CidrBlock used in VPC configuration. +The AWSCidrBlock defines the base label +type for AWSIpv4CidrBlock and AWSIpv6CidrBlock

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

cidr_block

The CIDR block

block_state

The state of the block

association_id

the association id if the block is associated to a VPC

lastupdated

Timestamp of the last time the node was updated

id

Unique identifier defined with the VPC association and the cidr_block

+
+
+

Relationships

+
    +
  • AWSVpc association

    +
    (AWSVpc)-[BLOCK_ASSOCIATION]->(AWSCidrBlock)
    +
    +
    +
  • +
  • Peering connection where AWSCidrBlock is an accepter or requester cidr.

    +
    (AWSCidrBlock)<-[REQUESTER_CIDR]-(AWSPeeringConnection)
    +(AWSCidrBlock)<-[ACCEPTER_CIDR]-(AWSPeeringConnection)
    +
    +
    +

    Example of high level view of peering (without security group permissions)

    +
    MATCH p=(:AWSAccount)-[:RESOURCE|BLOCK_ASSOCIATION*..]->(:AWSCidrBlock)<-[:ACCEPTER_CIDR]-(:AWSPeeringConnection)-[:REQUESTER_CIDR]->(:AWSCidrBlock)<-[:RESOURCE|BLOCK_ASSOCIATION*..]-(:AWSAccount)
    +RETURN p
    +
    +
    +

    Exploring detailed inbound peering rules

    +
    MATCH (outbound_account:AWSAccount)-[:RESOURCE|BLOCK_ASSOCIATION*..]->(:AWSCidrBlock)<-[:ACCEPTER_CIDR]-(:AWSPeeringConnection)-[:REQUESTER_CIDR]->(inbound_block:AWSCidrBlock)<-[:BLOCK_ASSOCIATION]-(inbound_vpc:AWSVpc)<-[:RESOURCE]-(inbound_account:AWSAccount)
    +WITH inbound_vpc, inbound_block, outbound_account, inbound_account
    +MATCH (inbound_range:IpRange{id: inbound_block.cidr_block})-[:MEMBER_OF_IP_RULE]->(inbound_rule:IpPermissionInbound)-[:MEMBER_OF_EC2_SECURITY_GROUP]->(inbound_group:EC2SecurityGroup)<-[:MEMBER_OF_EC2_SECURITY_GROUP]-(inbound_vpc)
    +RETURN outbound_account.name, inbound_account.name, inbound_range.range, inbound_rule.fromport, inbound_rule.toport, inbound_rule.protocol, inbound_group.name, inbound_vpc.id
    +
    +
    +
  • +
+
+
+
+

AWSGroup

+

Representation of AWS IAM Groups.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

path

The path to the group (IAM identifier, see linked docs above for details)

groupid

Unique string identifying the group

name

The friendly name that identifies the group

createdate

ISO 8601 date-time string when the group was created

arn

The AWS-global identifier for this group

+
+

Relationships

+
    +
  • Objects part of an AWSGroup may assume AWSRoles.

    +
    ```
    +(AWSGroup)-[STS_ASSUMEROLE_ALLOW]->(AWSRole)
    +```
    +
    +
    +
  • +
  • AWSUsers and AWSPrincipals can be members of AWSGroups.

    +
    ```
    +(AWSUser, AWSPrincipal)-[MEMBER_AWS_GROUP]->(AWSGroup)
    +```
    +
    +
    +
  • +
  • AWSGroups belong to AWSAccounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSGroup)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSInspectorFinding

+

Representation of an AWS Inspector Finding

+
+

Relationships

+
    +
  • AWSInspectorFinding may affect EC2 Instances

    +
    (AWSInspectorFinding)-[:AFFECTS]->(EC2Instance)
    +
    +
    +
  • +
  • AWSInspectorFinding may affect ECR Repositories

    +
    (AWSInspectorFinding)-[:AFFECTS]->(ECRRepository)
    +
    +
    +
  • +
  • AWSInspectorFinding may affect ECR Images

    +
    (AWSInspectorFinding)-[:AFFECTS]->(ECRImage)
    +
    +
    +
  • +
  • AWSInspectorFindings belong to AWSAccounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSInspectorFinding)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSInspectorPackage

+

Representation of an AWS Inspector Finding Package

+
+

Relationships

+
    +
  • AWSInspectorFindings have AWSInspectorPackages.

    +
    ```
    +(AWSInspectorFindings)-[HAS]->(AWSInspectorPackages)
    +```
    +
    +
    +
  • +
  • AWSInspectorPackages belong to AWSAccounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSInspectorPackages)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSLambda

+

Representation of an AWS Lambda Function.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The arn of the lambda function

name

The name of the lambda function

modifieddate

Timestamp of the last time the function was last updated

runtime

The runtime environment for the Lambda function

description

The description of the Lambda function

timeout

The amount of time in seconds that Lambda allows a function to run before stopping it

memory

The memory that’s allocated to the function

codesize

The size of the function’s deployment package, in bytes.

handler

The function that Lambda calls to begin executing your function.

version

The version of the Lambda function.

tracingconfigmode

The function’s AWS X-Ray tracing configuration mode.

revisionid

The latest updated revision of the function or alias.

state

The current state of the function.

statereason

The reason for the function’s current state.

statereasoncode

The reason code for the function’s current state.

lastupdatestatus

The status of the last update that was performed on the function.

lastupdatestatusreason

The reason for the last update that was performed on the function.

lastupdatestatusreasoncode

The reason code for the last update that was performed on the function.

packagetype

The type of deployment package.

signingprofileversionarn

The ARN of the signing profile version.

signingjobarn

The ARN of the signing job.

codesha256

The SHA256 hash of the function’s deployment package.

architectures

The instruction set architecture that the function supports. Architecture is a string array with one of the valid values.

masterarn

For Lambda@Edge functions, the ARN of the main function.

kmskeyarn

The KMS key that’s used to encrypt the function’s environment variables. This key is only returned if you’ve configured a customer managed key.

+
+

Relationships

+
    +
  • AWSLambda function are resources in an AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSLambda)
    +```
    +
    +
    +
  • +
  • AWSLambda functions may act as AWSPrincipals via role assumption.

    +
    ```
    +(AWSLambda)-[STS_ASSUME_ROLE_ALLOW]->(AWSPrincipal)
    +```
    +
    +
    +
  • +
  • AWSLambda functions may also have aliases.

    +
    ```
    +(AWSLambda)-[KNOWN_AS]->(AWSLambdaFunctionAlias)
    +```
    +
    +
    +
  • +
  • AWSLambda functions may have the resource AWSLambdaEventSourceMapping.

    +
    ```
    +(AWSLambda)-[RESOURCE]->(AWSLambdaEventSourceMapping)
    +```
    +
    +
    +
  • +
  • AWSLambda functions has AWS Lambda Layers.

    +
    ```
    +(AWSLambda)-[HAS]->(AWSLambdaLayer)
    +```
    +
    +
    +
  • +
  • AWSLambda functions has AWS ECR Images.

    +
    ```
    +(AWSLambda)-[HAS]->(ECRImage)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSLambdaFunctionAlias

+

Representation of an AWSLambdaFunctionAlias.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The arn of the lambda function alias

name

The name of the lambda function alias

functionversion

The function version that the alias invokes.

revisionid

A unique identifier that changes when you update the alias.

description

The description of the alias.

+
+

Relationships

+
    +
  • AWSLambda functions may also have aliases.

    +
    ```
    +(AWSLambda)-[KNOWN_AS]->(AWSLambdaFunctionAlias)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSLambdaEventSourceMapping

+

Representation of an AWSLambdaEventSourceMapping.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The id of the event source mapping

batchsize

The maximum number of items to retrieve in a single batch.

startingposition

The position in a stream from which to start reading.

startingpositiontimestamp

The time from which to start reading.

parallelizationfactor

The number of batches to process from each shard concurrently.

maximumbatchingwindowinseconds

The maximum amount of time to gather records before invoking the function, in seconds.

eventsourcearn

The Amazon Resource Name (ARN) of the event source.

lastmodified

The date that the event source mapping was last updated, or its state changed.

state

The state of the event source mapping.

maximumrecordage

Discard records older than the specified age.

bisectbatchonfunctionerror

If the function returns an error, split the batch in two and retry.

maximumretryattempts

Discard records after the specified number of retries.

tumblingwindowinseconds

The duration in seconds of a processing window.

lastprocessingresult

The result of the last AWS Lambda invocation of your Lambda function.

+
+

Relationships

+
    +
  • AWSLambda functions may have the resource AWSLambdaEventSourceMapping.

    +
    ```
    +(AWSLambda)-[RESOURCE]->(AWSLambdaEventSourceMapping)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSLambdaLayer

+

Representation of an AWSLambdaLayer.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The arn of the lambda function layer

codesize

The size of the layer archive in bytes.

signingprofileversionarn

The Amazon Resource Name (ARN) for a signing profile version.

signingjobarn

The Amazon Resource Name (ARN) of a signing job.

+
+

Relationships

+
    +
  • AWSLambda functions has AWS Lambda Layers.

    +
    ```
    +(AWSLambda)-[HAS]->(AWSLambdaLayer)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSPolicy

+

Representation of an AWS Policy.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

name

The friendly name (not ARN) identifying the policy

createdate

ISO 8601 date-time when the policy was created

type

“inline” or “managed” - the type of policy it is

arn

The arn for this object

id

The unique identifer for a policy. If the policy is managed this will be the Arn. If the policy is inline this will calculated as AWSPrincipal/inline_policy/PolicyName

+
+

Relationships

+
    +
  • AWSPrincipal contains AWSPolicy

    +
    ```
    +(AWSPrincipal)-[POLICY]->(AWSPolicy)
    +```
    +
    +
    +
  • +
  • AWSPolicy contains AWSPolicyStatement

    +
    ```
    +(AWSPolicy)-[STATEMENTS]->(AWSPolicyStatement)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSPolicyStatement

+

Representation of an AWS Policy Statement.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

resources

(array) The resources the statement is applied to. Can contain wildcards

actions

(array) The permissions allowed or denied by the statement. Can contain wildcards

notactions

(array) The permission explicitly not matched by the statement

effect

“Allow” or “Deny” - the effect of this statement

id

The unique identifier for a statement.
If the statement has an Sid the id will be calculated as AWSPolicy.id/statements/Sid.
If the statement has no Sid the id will be calculated as AWSPolicy.id/statements/index of statement in statement list

+
+

Relationships

+
    +
  • AWSPolicy contains AWSPolicyStatement

    +
    ```
    +(AWSPolicy)-[STATEMENTS]->(AWSPolicyStatement)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSPrincipal

+

Representation of an AWSPrincipal.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

path

The path to the principal

name

The friendly name of the principal

createdate

ISO 8601 date-time when the principal was created

arn

AWS-unique identifier for this object

userid

The stable and unique string identifying the principal.

passwordlastused

Datetime when this principal’s password was last used

+
+

Relationships

+
    +
  • AWS Principals can be members of AWS Groups.

    +
    ```
    +(AWSPrincipal)-[MEMBER_AWS_GROUP]->(AWSGroup)
    +```
    +
    +
    +
  • +
  • This AccountAccessKey is used to authenticate to this AWSPrincipal.

    +
    ```
    +(AWSPrincipal)-[AWS_ACCESS_KEY]->(AccountAccessKey)
    +```
    +
    +
    +
  • +
  • AWS Roles can trust AWS Principals.

    +
    (AWSRole)-[TRUSTS_AWS_PRINCIPAL]->(AWSPrincipal)
    +
    +
    +
  • +
  • AWS Accounts contain AWS Principals.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSPrincipal)
    +```
    +
    +
    +
  • +
  • Redshift clusters may assume IAM roles. See this article.

    +
    (RedshiftCluster)-[STS_ASSUMEROLE_ALLOW]->(AWSPrincipal)
    +
    +
    +
  • +
+
+
+
+

AWSPrincipal::AWSUser

+

Representation of an AWSUser. An AWS User is a type of AWS Principal.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

path

The path to the user

name

The friendly name of the user

createdate

ISO 8601 date-time when the user was created

arn

AWS-unique identifier for this object

userid

The stable and unique string identifying the user.

passwordlastused

Datetime when this user’s password was last used

+
+

Relationships

+
    +
  • AWS Users can be members of AWS Groups.

    +
    ```
    +(AWSUser)-[MEMBER_AWS_GROUP]->(AWSGroup)
    +```
    +
    +
    +
  • +
  • AWS Users can assume AWS Roles.

    +
    ```
    +(AWSUser)-[STS_ASSUMEROLE_ALLOW]->(AWSRole)
    +```
    +
    +
    +
  • +
  • This AccountAccessKey is used to authenticate to this AWSUser

    +
    ```
    +(AWSUser)-[AWS_ACCESS_KEY]->(AccountAccessKey)
    +```
    +
    +
    +
  • +
  • AWS Accounts contain AWS Users.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSUser)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSPrincipal::AWSRole

+

Representation of an AWS IAM Role. An AWS Role is a type of AWS Principal.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

roleid

The stable and unique string identifying the role.

name

The friendly name that identifies the role.

createdate

The date and time, in ISO 8601 date-time format, when the role was created.

arn

AWS-unique identifier for this object

+
+

Relationships

+
    +
  • Some AWS Groups, Users, Principals, and EC2 Instances can assume AWS Roles.

    +
    (AWSGroup, AWSUser, EC2Instance)-[STS_ASSUMEROLE_ALLOW]->(AWSRole)
    +
    +
    +
  • +
  • Some AWS Roles can assume other AWS Roles.

    +
    (AWSRole)-[STS_ASSUMEROLE_ALLOW]->(AWSRole)
    +
    +
    +
  • +
  • Some AWS Roles trust AWS Principals.

    +
    (AWSRole)-[TRUSTS_AWS_PRINCIPAL]->(AWSPrincipal)
    +
    +
    +
  • +
  • AWS Roles are defined in AWS Accounts.

    +
    (AWSAccount)-[RESOURCE]->(AWSRole)
    +
    +
    +
  • +
+
+
+
+

AWSTransitGateway

+

Representation of an AWS Transit Gateway.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

owner_id

The ID of the AWS account that owns the transit gateway

description

Transit Gateway description

state

Can be one of pending | available | modifying | deleting | deleted

tgw_id

Unique identifier of the Transit Gateway

id

Unique identifier of the Transit Gateway

arn

AWS-unique identifier for this object (same as id)

+
+

Relationships

+
    +
  • Transit Gateways belong to one AWSAccount

    +
    (AWSAccount)-[RESOURCE]->(AWSTransitGateway)
    +
    +
    +
  • +
  • … and can be shared with other accounts

    +
    (AWSAccount)<-[SHARED_WITH]-(AWSTransitGateway)
    +
    +
    +
  • +
  • AWSTag

    +
    (AWSTransitGateway)-[TAGGED]->(AWSTag)
    +
    +
    +
  • +
+
+
+
+

AWSTransitGatewayAttachment

+

Representation of an AWS Transit Gateway Attachment.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

resource_type

Can be one of vpc | vpn | direct-connect-gateway | tgw-peering

state

Can be one of initiating | pendingAcceptance | rollingBack | pending | available | modifying | deleting | deleted | failed | rejected | rejecting | failing

id

Unique identifier of the Transit Gateway Attachment

+
+

Relationships

+
    +
  • AWSAccount

    +
    (AWSAccount)-[RESOURCE]->(AWSTransitGatewayAttachment)
    +
    +
    +
  • +
  • AWSVpc (for VPC attachments)

    +
    (AWSVpc)-[RESOURCE]->(AWSTransitGatewayAttachment {resource_type: 'vpc'})
    +
    +
    +
  • +
  • AWSTransitGateway attachment

    +
    (AWSTransitGateway)<-[ATTACHED_TO]-(AWSTransitGatewayAttachment)
    +
    +
    +
  • +
  • AWSTag

    +
    (AWSTransitGatewayAttachment)-[TAGGED]->(AWSTag)
    +
    +
    +
  • +
+
+
+
+

AWSVpc

+

Representation of an AWS CidrBlock used in VPC configuration. +More information on https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-vpcs.html

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

vpcid

The VPC unique identifier

primary_cidr_block

The primary IPv4 CIDR block for the VPC.

instance_tenancy

The allowed tenancy of instances launched into the VPC.

state

The current state of the VPC.

region

(optional) the region of this VPC. This field is only available on VPCs in your account. It is not available on VPCs that are external to your account and linked via a VPC peering relationship.

id

Unique identifier defined VPC node (vpcid)

+
+

Relationships

+
    +
  • AWSAccount resource

    +
    (AWSAccount)-[RESOURCE]->(AWSVpc)
    +
    +
    +
  • +
  • AWSVpc and AWSCidrBlock association

    +
    (AWSVpc)-[BLOCK_ASSOCIATION]->(AWSCidrBlock)
    +
    +
    +
  • +
  • AWSVpc and EC2SecurityGroup membership association

    +
    (AWSVpc)<-[MEMBER_OF_EC2_SECURITY_GROUP]-(EC2SecurityGroup)
    +
    +
    +
  • +
  • AWS VPCs can be tagged with AWSTags.

    +
    (AWSVpc)-[TAGGED]->(AWSTag)
    +
    +
    +
  • +
  • Redshift clusters can be members of AWSVpcs.

    +
    (RedshiftCluster)-[MEMBER_OF_AWS_VPC]->(AWSVpc)
    +
    +
    +
  • +
  • Peering connection where AWSVpc is an accepter or requester vpc.

    +
    (AWSVpc)<-[REQUESTER_VPC]-(AWSPeeringConnection)
    +(AWSVpc)<-[ACCEPTER_VPC]-(AWSPeeringConnection)
    +
    +
    +
  • +
+
+
+
+

Tag::AWSTag

+

Representation of an AWS Tag. AWS Tags can be applied to many objects.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

This tag’s unique identifier of the format {TagKey}:{TagValue}. We fabricated this ID.

key

One part of a key-value pair that makes up a tag.

value

One part of a key-value pair that makes up a tag.

region

The region where this tag was discovered.

+
+

Relationships

+
    +
  • AWS VPCs, DB Subnet Groups, EC2 Instances, EC2 SecurityGroups, EC2 Subnets, EC2 Network Interfaces, RDS Instances, and S3 Buckets can be tagged with AWSTags.

    +
    (AWSVpc, DBSubnetGroup, EC2Instance, EC2SecurityGroup, EC2Subnet, NetworkInterface, RDSInstance, S3Bucket)-[TAGGED]->(AWSTag)
    +
    +
    +
  • +
+
+
+
+

AccountAccessKey

+

Representation of an AWS Access Key.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

createdate

Date when access key was created

status

Active: valid for API calls. Inactive: not valid for API calls

lastuseddate

Date when the key was last used

lastusedservice

The service that was last used with the access key

lastusedregion

The region where the access key was last used

accesskeyid

The ID for this access key

+
+

Relationships

+
    +
  • Account Access Keys may authenticate AWS Users and AWS Principal objects.

    +
    ```
    +(AWSUser, AWSPrincipal)-[AWS_ACCESS_KEY]->(AccountAccessKey)
    +```
    +
    +
    +
  • +
+
+
+
+

DBSubnetGroup

+

Representation of an RDS DB Subnet Group. For more information on how RDS instances interact with these, please see this article.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

id

The ARN of the DBSubnetGroup

name

The name of DBSubnetGroup

lastupdated

Timestamp of the last time the node was updated

description

Description of the DB Subnet Group

status

The status of the group

vpc_id

The ID of the VPC (Virtual Private Cloud) that this DB Subnet Group is associated with.

value

The IP address that the DNSRecord points to

+
+

Relationships

+
    +
  • RDS Instances are part of DB Subnet Groups

    +
    (RDSInstance)-[:MEMBER_OF_DB_SUBNET_GROUP]->(DBSubnetGroup)
    +
    +
    +
  • +
  • DB Subnet Groups consist of EC2 Subnets

    +
    (DBSubnetGroup)-[:RESOURCE]->(EC2Subnet)
    +
    +
    +
  • +
  • DB Subnet Groups can be tagged with AWSTags.

    +
    ```
    +(DBSubnetGroup)-[TAGGED]->(AWSTag)
    +```
    +
    +
    +
  • +
+
+
+
+

DNSRecord

+

Representation of a generic DNSRecord.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

name

The name of the DNSRecord

lastupdated

Timestamp of the last time the node was updated

id

The name of the DNSRecord concatenated with the record type

type

The record type of the DNS record

value

The IP address that the DNSRecord points to

+
+

Relationships

+
    +
  • DNSRecords can point to IP addresses.

    +
    ```
    +(DNSRecord)-[DNS_POINTS_TO]->(Ip)
    +```
    +
    +
    +
  • +
  • DNSRecords/AWSDNSRecords can point to each other.

    +
    ```
    +(AWSDNSRecord, DNSRecord)-[DNS_POINTS_TO]->(AWSDNSRecord, DNSRecord)
    +```
    +
    +
    +
  • +
  • DNSRecords can point to LoadBalancers.

    +
    ```
    +(DNSRecord)-[DNS_POINTS_TO]->(LoadBalancer)
    +```
    +
    +
    +
  • +
  • DNSRecords can be members of DNSZones.

    +
    ```
    +(DNSRecord)-[MEMBER_OF_DNS_ZONE]->(DNSZone)
    +```
    +
    +
    +
  • +
+
+
+
+

DNSRecord::AWSDNSRecord

+

Representation of an AWS DNS ResourceRecordSet.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

name

The name of the DNSRecord

lastupdated

Timestamp of the last time the node was updated

id

The zoneid for the record, the value of the record, and the type concatenated together

type

The record type of the DNS record

value

If it is an A, ALIAS, or CNAME record, this is the IP address that the DNSRecord points to. If it is an NS record, the name is used here.

+
+

Relationships

+
    +
  • DNSRecords/AWSDNSRecords can point to each other.

    +
    ```
    +(AWSDNSRecord, DNSRecord)-[DNS_POINTS_TO]->(AWSDNSRecord, DNSRecord)
    +```
    +
    +
    +
  • +
  • AWSDNSRecords can point to LoadBalancers.

    +
    ```
    +(AWSDNSRecord)-[DNS_POINTS_TO]->(LoadBalancer, ESDomain)
    +```
    +
    +
    +
  • +
  • AWSDNSRecords can be members of AWSDNSZones.

    +
    ```
    +(AWSDNSRecord)-[MEMBER_OF_DNS_ZONE]->(AWSDNSZone)
    +```
    +
    +
    +
  • +
+
+
+
+

DNSZone

+

Representation of a generic DNS Zone.

+ ++++ + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

name

the name of the DNS zone

comment

Comments about the zone

+
+

Relationships

+
    +
  • DNSRecords can be members of DNSZones.

    +
    ```
    +(DNSRecord)-[MEMBER_OF_DNS_ZONE]->(DNSZone)
    +```
    +
    +
    +
  • +
+
+
+
+

DNSZone::AWSDNSZone

+

Representation of an AWS DNS HostedZone.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

name

the name of the DNS zone

zoneid

The zoneid defined by Amazon Route53

lastupdated

Timestamp of the last time the node was updated

comment

Comments about the zone

privatezone

Whether or not this is a private DNS zone

+
+

Relationships

+
    +
  • AWSDNSZones and DNSZones can be part of AWSAccounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSDNSZone)
    +```
    +
    +
    +
  • +
  • AWSDNSRecords can be members of AWSDNSZones.

    +
    ```
    +(AWSDNSRecord)-[MEMBER_OF_DNS_ZONE]->(AWSDNSZone)
    +```
    +
    +
    +
  • +
  • AWSDNSZone can have subzones hosted by another AWSDNSZone

    +
    ```
    +(AWSDNSZone)<-[SUBZONE]-(AWSDNSZone)
    +```
    +
    +
    +
  • +
+
+
+
+

DynamoDBTable

+

Representation of an AWS DynamoDBTable.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

name

The name of the table

id

The ARN of the table

region

The AWS region of the table

arn

The AWS-unique identifier

+
+

Relationships

+
    +
  • DynamoDBTables belong to AWS Accounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(DynamoDBTable)
    +```
    +
    +
    +
  • +
+
+
+
+

EC2Instance

+

Our representation of an AWS EC2 Instance.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Same as instanceid below.

instanceid

The instance id provided by AWS. This is globally unique

publicdnsname

The public DNS name assigned to the instance

publicipaddress

The public IPv4 address assigned to the instance if applicable

privateipaddress

The private IPv4 address assigned to the instance

imageid

The ID of the Amazon Machine Image used to launch the instance

subnetid

The ID of the EC2Subnet associated with this instance

instancetype

The instance type. See API docs linked above for specifics.

iaminstanceprofile

The IAM instance profile associated with the instance, if applicable.

launchtime

The time the instance was launched

monitoringstate

Whether monitoring is enabled. Valid Values: disabled, disabling, enabled, pending.

state

The current state of the instance.

launchtimeunix

The time the instance was launched in unix time

region

The AWS region this Instance is running in

exposed_internet

The exposed_internet flag on an EC2 instance is set to True when (1) the instance is part of an EC2 security group or is connected to a network interface connected to an EC2 security group that allows connectivity from the 0.0.0.0/0 subnet or (2) the instance is connected to an Elastic Load Balancer that has its own exposed_internet flag set to True.

availabilityzone

The Availability Zone of the instance.

tenancy

The tenancy of the instance.

hostresourcegrouparn

The ARN of the host resource group in which to launch the instances.

platform

The value is Windows for Windows instances; otherwise blank.

architecture

The architecture of the image.

ebsoptimized

Indicates whether the instance is optimized for Amazon EBS I/O.

bootmode

The boot mode of the instance.

instancelifecycle

Indicates whether this is a Spot Instance or a Scheduled Instance.

hibernationoptions

Indicates whether the instance is enabled for hibernation.

+
+

Relationships

+
    +
  • EC2 Instances can be part of subnets

    +
    ```
    +(EC2Instance)-[PART_OF_SUBNET]->(EC2Subnet)
    +```
    +
    +
    +
  • +
  • EC2 Instances can have NetworkInterfaces connected to them

    +
    ```
    +(EC2Instance)-[NETWORK_INTERFACE]->(NetworkInterface)
    +```
    +
    +
    +
  • +
  • EC2 Instances may be members of EC2 Reservations

    +
    ```
    +(EC2Instance)-[MEMBER_OF_EC2_RESERVATION]->(EC2Reservation)
    +```
    +
    +
    +
  • +
  • EC2 Instances can be part of EC2 Security Groups

    +
    ```
    +(EC2Instance)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup)
    +```
    +
    +
    +
  • +
  • Load Balancers can expose (be connected to) EC2 Instances

    +
    ```
    +(LoadBalancer)-[EXPOSE]->(EC2Instance)
    +```
    +
    +
    +
  • +
  • Package and Dependency nodes can be deployed in EC2 Instances.

    +
    ```
    +(Package, Dependency)-[DEPLOYED]->(EC2Instance)
    +```
    +
    +
    +
  • +
  • AWS Accounts contain EC2 Instances.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(EC2Instance)
    +```
    +
    +
    +
  • +
  • EC2 Instances can be tagged with AWSTags.

    +
    ```
    +(EC2Instance)-[TAGGED]->(AWSTag)
    +```
    +
    +
    +
  • +
  • AWS EBS Volumes are attached to an EC2 Instance

    +
    ```
    +(EBSVolume)-[ATTACHED_TO]->(EC2Instance)
    +```
    +
    +
    +
  • +
  • EC2 Instances can assume IAM Roles.

    +
    ```
    +(EC2Instance)-[STS_ASSUMEROLE_ALLOW]->(AWSRole)
    +```
    +
    +
    +
  • +
  • EC2Instances can have SSMInstanceInformation

    +
    ```
    +(EC2Instance)-[HAS_INFORMATION]->(SSMInstanceInformation)
    +```
    +
    +
    +
  • +
  • EC2Instances can have SSMInstancePatches

    +
    ```
    +(EC2Instance)-[HAS_PATCH]->(SSMInstancePatch)
    +```
    +
    +
    +
  • +
+
+
+
+

EC2KeyPair

+

Representation of an AWS EC2 Key Pair

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

keyname

The name of the key pair

keyfingerprint

The fingerprint of the public key

region

The AWS region

arn

AWS-unique identifier for this object

id

same as arn

user_uploaded

user_uploaded is set to True if the the KeyPair was uploaded to AWS. Uploaded KeyPairs will have 128-bit MD5 hashed keyfingerprint, and KeyPairs from AWS will have 160-bit SHA-1 hashed keyfingerprints.

duplicate_keyfingerprint

duplicate_keyfingerprint is set to True if the KeyPair has the same keyfingerprint as another KeyPair.

+
+

Relationships

+
    +
  • EC2 key pairs are contained in AWS Accounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(EC2KeyPair)
    +```
    +
    +
    +
  • +
  • EC2 key pairs can be used to log in to AWS EC2 isntances.

    +
    ```
    +(EC2KeyPair)-[SSH_LOGIN_TO]->(EC2Instance)
    +```
    +
    +
    +
  • +
  • EC2 key pairs have matching keyfingerprint.

    +
    ```
    +(EC2KeyPair)-[MATCHING_FINGERPRINT]->(EC2KeyPair)
    +```
    +
    +
    +
  • +
+
+
+
+

EC2PrivateIp

+

Representation of an AWS EC2 InstancePrivateIpAddress

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

network_interface_id

id of the network interface with which the IP is associated with

primary

Indicates whether this IPv4 address is the primary private IP address of the network interface.

private_ip_address

The private IPv4 address of the network interface.

public_ip

The public IP address or Elastic IP address bound to the network interface.

ip_owner_id

Id of the owner, e.g. amazon-elb for ELBs

+
+

Relationships

+
    +
  • EC2PrivateIps are connected with NetworkInterfaces.

    +
    ```
    +(NetworkInterface)-[PRIVATE_IP_ADDRESS]->(EC2PrivateIp)
    +```
    +
    +
    +
  • +
+
+
+
+

EC2Reservation

+

Representation of an AWS EC2 Reservation.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

requesterid

The ID of the requester that launched the instances on your behalf

reservationid

The ID of the reservation.

region

The AWS region

ownerid

The ID of the AWS account that owns the reservation.

+
+

Relationships

+
    +
  • EC2 reservations are contained in AWS Accounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(EC2Reservation)
    +```
    +
    +
    +
  • +
  • EC2 Instances are members of EC2 reservations.

    +
    ```
    +(EC2Instance)-[MEMBER_OF_EC2_RESERVATION]->(EC2Reservation)
    +```
    +
    +
    +
  • +
+
+
+
+

EC2SecurityGroup

+

Representation of an AWS EC2 Security Group.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

groupid

The ID of the security group

name

The name of the security group

description

A description of the security group

id

Same as groupid

region

The AWS region this security group is installed in

+
+

Relationships

+
    +
  • EC2 Instances, Network Interfaces, Load Balancers, Elastic Search Domains, IP Rules, IP Permission Inbound nodes, and RDS Instances can be members of EC2 Security Groups.

    +
    ```
    +(EC2Instance,
    + NetworkInterface,
    + LoadBalancer,
    + ESDomain,
    + IpRule,
    + IpPermissionInbound,
    + RDSInstance,
    + AWSVpc)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup)
    +```
    +
    +
    +
  • +
  • Load balancers can define inbound Source Security Groups.

    +
    ```
    +(LoadBalancer)-[SOURCE_SECURITY_GROUP]->(EC2SecurityGroup)
    +```
    +
    +
    +
  • +
  • AWS Accounts contain EC2 Security Groups.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(EC2SecurityGroup)
    +```
    +
    +
    +
  • +
  • EC2 SecurityGroups can be tagged with AWSTags.

    +
    ```
    +(EC2SecurityGroup)-[TAGGED]->(AWSTag)
    +```
    +
    +
    +
  • +
  • Redshift clusters can be members of EC2 Security Groups.

    +
    (RedshiftCluster)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup)
    +
    +
    +
  • +
+
+
+
+

EC2Subnet

+

Representation of an AWS EC2 Subnet.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

subnetid

The ID of the subnet

id

same as subnetid

region

The AWS region the subnet is installed on

name

The IPv4 CIDR block assigned to the subnet

cidr_block

The IPv4 CIDR block assigned to the subnet

available_ip_address_count

The number of unused private IPv4 addresses in the subnet. The IPv4 addresses for any stopped instances are considered unavailable

default_for_az

Indicates whether this is the default subnet for the Availability Zone.

map_customer_owned_ip_on_launch

Indicates whether a network interface created in this subnet (including a network interface created by RunInstances ) receives a customer-owned IPv4 address

map_public_ip_on_launch

Indicates whether instances launched in this subnet receive a public IPv4 address

subnet_arn

The Amazon Resource Name (ARN) of the subnet

availability_zone

The Availability Zone of the subnet

availability_zone_id

The AZ ID of the subnet

state

The current state of the subnet.

assignipv6addressoncreation

Indicates whether a network interface created in this subnet (including a network interface created by RunInstances ) receives an IPv6 address.

+
+

Relationships

+
    +
  • A Network Interface can be part of an EC2 Subnet.

    +
    ```
    +(NetworkInterface)-[PART_OF_SUBNET]->(EC2Subnet)
    +```
    +
    +
    +
  • +
  • An EC2 Instance can be part of an EC2 Subnet.

    +
    ```
    +(EC2Instance)-[PART_OF_SUBNET]->(EC2Subnet)
    +```
    +
    +
    +
  • +
  • A LoadBalancer can be part of an EC2 Subnet.

    +
    ```
    +(LoadBalancer)-[SUBNET]->(EC2Subnet)
    +
    +```
    +
    +
    +
  • +
  • A LoadBalancer can be part of an EC2 Subnet.

    +
    ```
    +(LoadBalancer)-[PART_OF_SUBNET]->(EC2Subnet)
    +```
    +
    +
    +
  • +
  • A LoadBalancerV2 can be part of an EC2 Subnet.

    +
    ```
    +(LoadBalancerV2)-[PART_OF_SUBNET]->(EC2Subnet)
    +```
    +
    +
    +
  • +
  • DB Subnet Groups consist of EC2 Subnets

    +
    (DBSubnetGroup)-[RESOURCE]->(EC2Subnet)
    +
    +
    +
  • +
  • EC2 Subnets can be tagged with AWSTags.

    +
    ```
    +(EC2Subnet)-[TAGGED]->(AWSTag)
    +```
    +
    +
    +
  • +
  • EC2 Subnets are member of a VPC.

    +
    ```
    +(EC2Subnet)-[MEMBER_OF_AWS_VPC]->(AWSVpc)
    +```
    +
    +
    +
  • +
  • EC2 Subnets belong to AWS Accounts

    +
    ```
    +(AWSAccount)-[RESOURCE]->(EC2Subnet)
    +```
    +
    +
    +
  • +
  • EC2PrivateIps are connected with NetworkInterfaces.

    +
    (NetworkInterface)-[PRIVATE_IP_ADDRESS]->(EC2PrivateIp)
    +
    +
    +
  • +
+
+
+
+

AWSInternetGateway

+
+

Representation of an AWS Interent Gateway.

+
+ ++++ + + + + + + + + + + + + + + + + +

Field

Description

id

Internet gateway ID

arn

Amazon Resource Name

region

The region of the gateway

+
+

Relationships

+
    +
  • Internet Gateways are attached to a VPC.

    +
    ```
    +(AWSInternetGateway)-[ATTACHED_TO]->(AWSVpc)
    +```
    +
    +
    +
  • +
  • Internet Gateways belong to AWS Accounts

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSInternetGateway)
    +```
    +
    +
    +
  • +
+
+
+
+

ECRRepository

+

Representation of an AWS Elastic Container Registry Repository.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

id

Same as ARN

arn

The ARN of the repository

name

The name of the repository

region

The region of the repository

created_at

Date and time when the repository was created

+
+

Relationships

+
    +
  • An ECRRepository contains ECRRepositoryImages:

    +
    (:ECRRepository)-[:REPO_IMAGE]->(:ECRRepositoryImage)
    +
    +
    +
  • +
+
+
+
+

ECRRepositoryImage

+

An ECR image may be referenced and tagged by more than one ECR Repository. To best represent this, we’ve created an +ECRRepositoryImage node as a layer of indirection between the repo and the image.

+

More concretely explained, we run +``ecr.list_images()` <https://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_ImageIdentifier.html>`_, and then +store the image tag on an ECRRepositoryImage node and the image digest hash on a separate ECRImage node.

+

This way, more than one ECRRepositoryImage can reference/be connected to the same ECRImage.

+ ++++ + + + + + + + + + + + + + + + + +

Field

Description

tag

The tag applied to the repository image, e.g. “latest”

uri

The URI where the repository image is stored

id

same as uri

+
+

Relationships

+
    +
  • An ECRRepository contains ECRRepositoryImages:

    +
    (:ECRRepository)-[:REPO_IMAGE]->(:ECRRepositoryImage)
    +
    +
    +
  • +
  • ECRRepositoryImages reference ECRImages

    +
    (:ECRRepositoryImage)-[:IMAGE]->(:ECRImage)
    +
    +
    +
  • +
+
+
+
+

ECRImage

+

Representation of an ECR image identified by its digest (e.g. a SHA hash). Specifically, this is the “digest part” of +``ecr.list_images()` <https://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_ImageIdentifier.html>`_. Also see +ECRRepositoryImage.

+ ++++ + + + + + + + + + + + + + +

Field

Description

digest

The hash of this ECR image

id

Same as digest

+
+

Relationships

+
    +
  • ECRRepositoryImages reference ECRImages

    +
    (:ECRRepositoryImage)-[:IMAGE]->(:ECRImage)
    +
    +
    +
  • +
  • Software packages are a part of ECR Images

    +
    (:Package)-[:DEPLOYED]->(:ECRImage)
    +
    +
    +
  • +
+
+
+
+

Package

+

Representation of a software package, as found by an AWS ECR vulnerability scan.

+ ++++ + + + + + + + + + + + + + + + + +

Field

Description

id

Concatenation of {version}|{name}

version

The version of the package, includes the Linux distro that it was built for

name

The name of the package

+
+

Relationships

+
    +
  • Software packages are a part of ECR Images

    +
    (:Package)-[:DEPLOYED]->(:ECRImage)
    +
    +
    +
  • +
  • AWS ECR scans yield ECRScanFindings that affect software packages

    +
    (:ECRScanFindings)-[:AFFECTS]->(:Package)
    +
    +
    +
  • +
+
+
+
+

ECRScanFinding (:Risk:CVE)

+

Representation of a scan finding from AWS ECR. This is the result output of ``ecr.describe_image_scan_findings()` <https://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_DescribeImageScanFindings.html>`_.

+ ++++ + + + + + + + + + + + + + + + + + + + +

Field

Description

name

The name of the ECR scan finding, e.g. a CVE name

id

Same as name

severity

The severity of the risk

uri

A URI link to a descriptive article on the risk

+
+

Relationships

+
    +
  • AWS ECR scans yield ECRScanFindings that affect software packages

    +
    (:ECRScanFindings)-[:AFFECTS]->(:Package)
    +
    +
    +
  • +
+
+
+
+

EKSCluster

+

Representation of an AWS EKS Cluster.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

created_at

The date and time the cluster was created

region

The AWS region

arn

AWS-unique identifier for this object

id

same as arn

name

Name of the EKS Cluster

endpoint

The endpoint for the Kubernetes API server.

endpoint_public_access

Indicates whether the Amazon EKS public API server endpoint is enabled

exposed_internet

Set to True if the EKS Cluster public API server endpoint is enabled

rolearn

The ARN of the IAM role that provides permissions for the Kubernetes control plane to make calls to AWS API

version

Kubernetes version running

platform_version

Version of EKS

status

Status of the cluster. Valid Values: creating, active, deleting, failed, updating

audit_logging

Whether audit logging is enabled

+
+

Relationships

+
    +
  • EKS Clusters belong to AWS Accounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(EKSCluster)
    +```
    +
    +
    +
  • +
+
+
+
+

EMRCluster

+

Representation of an AWS EMR Cluster.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

region

The AWS region

arn

AWS-unique identifier for this object

id

The Id of the EMR Cluster.

instance_collection_type

The instance group configuration of the cluster. A value of INSTANCE_GROUP indicates a uniform instance group configuration. A value of INSTANCE_FLEET indicates an instance fleets configuration.

log_encryption_kms_key_id

The KMS key used for encrypting log files.

requested_ami_version

The AMI version requested for this cluster.

running_ami_version

The AMI version running on this cluster.

release_label

The Amazon EMR release label, which determines the version of open-source application packages installed on the cluster.

auto_terminate

Specifies whether the cluster should terminate after completing all steps.

termination_protected

Indicates whether Amazon EMR will lock the cluster to prevent the EC2 instances from being terminated by an API call or user intervention, or in the event of a cluster error.

visible_to_all_users

Indicates whether the cluster is visible to IAM principals in the Amazon Web Services account associated with the cluster.

master_public_dns_name

The DNS name of the master node. If the cluster is on a private subnet, this is the private DNS name. On a public subnet, this is the public DNS name.

security_configuration

The name of the security configuration applied to the cluster.

autoscaling_role

An IAM role for automatic scaling policies.

scale_down_behavior

The way that individual Amazon EC2 instances terminate when an automatic scale-in activity occurs or an instance group is resized.

custom_ami_id

The ID of a custom Amazon EBS-backed Linux AMI if the cluster uses a custom AMI.

repo_upgrade_on_boot

Specifies the type of updates that are applied from the Amazon Linux AMI package repositories when an instance boots using the AMI.

outpost_arn

The Amazon Resource Name (ARN) of the Outpost where the cluster is launched.

log_uri

The path to the Amazon S3 location where logs for this cluster are stored.

servicerole

Service Role of the EMR Cluster

+
+

Relationships

+
    +
  • EMR Clusters belong to AWS Accounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(EMRCluster)
    +```
    +
    +
    +
  • +
+
+
+
+

ESDomain

+

Representation of an AWS ElasticSearch Domain (see ElasticsearchDomainConfig).

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

elasticsearch_cluster_config_instancetype

The instancetype

elasticsearch_version

The version of elasticsearch

elasticsearch_cluster_config_zoneawarenessenabled

Indicates whether multiple Availability Zones are enabled.

elasticsearch_cluster_config_dedicatedmasterenabled

Indicates whether dedicated master nodes are enabled for the cluster. True if the cluster will use a dedicated master node. False if the cluster will not.

elasticsearch_cluster_config_dedicatedmastercount

Number of dedicated master nodes in the cluster.

elasticsearch_cluster_config_dedicatedmastertype

Amazon ES instance type of the dedicated master nodes in the cluster.

domainid

Unique identifier for an Amazon ES domain.

encryption_at_rest_options_enabled

Specify true to enable encryption at rest.

deleted

Status of the deletion of an Amazon ES domain. True if deletion of the domain is complete. False if domain deletion is still in progress.

id

same as domainid

arn

Amazon Resource Name (ARN) of an Amazon ES domain.

exposed_internet

exposed_internet is set to True if the ElasticSearch domain has a policy applied to it that makes it internet-accessible. This policy determination is made by using the policyuniverse library. The code for this augmentation is implemented at cartography.intel.aws.elasticsearch._process_access_policy().

+
+

Relationships

+
    +
  • Elastic Search domains can be members of EC2 Security Groups.

    +
    ```
    +(ESDomain)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup)
    +```
    +
    +
    +
  • +
  • Elastic Search domains belong to AWS Accounts.

    +
    (AWSAccount)-[RESOURCE]->(ESDomain)
    +
    +
    +
  • +
  • DNS Records can point to Elastic Search domains.

    +
    ```
    +(DNSRecord)-[DNS_POINTS_TO]->(ESDomain)
    +```
    +
    +
    +
  • +
+
+
+
+

Endpoint

+

Representation of a generic network endpoint.

+ ++++ + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

protocol

The protocol of this endpoint

port

The port of this endpoint

+
+

Relationships

+
    +
  • Endpoints can be installed load balancers, though more specifically we would refer to these Endpoint nodes as ELBListeners.

    +
    ```
    +(LoadBalancer)-[ELB_LISTENER]->(Endpoint)
    +```
    +
    +
    +
  • +
+
+
+
+

Endpoint::ELBListener

+

Representation of an AWS Elastic Load Balancer Listener. Here, an ELBListener is a more specific type of Endpoint. Here’a good introduction.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

protocol

The protocol of this endpoint

port

The port of this endpoint

policy_names

A list of SSL policy names set on the listener.

id

The ELB ID. This is a concatenation of the DNS name, port, and protocol.

instance_port

The port open on the EC2 instance that this listener is connected to

instance_protocol

The protocol defined on the EC2 instance that this listener is connected to

+
+

Relationships

+
    +
  • A ELBListener is installed on a load balancer.

    +
    ```
    +(LoadBalancer)-[ELB_LISTENER]->(ELBListener)
    +```
    +
    +
    +
  • +
+
+
+
+

Endpoint::ELBV2Listener

+

Representation of an AWS Elastic Load Balancer V2 Listener.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

protocol

The protocol of this endpoint - One of 'HTTP''HTTPS''TCP''TLS''UDP''TCP_UDP'

port

The port of this endpoint

ssl_policy

Only set for HTTPS or TLS listener. The security policy that defines which protocols and ciphers are supported.

targetgrouparn

The ARN of the Target Group, if the Action type is forward.

+
+

Relationships

+
    +
  • A ELBV2Listener is installed on a LoadBalancerV2.

    +
    ```
    +(elbv2)-[r:ELBV2_LISTENER]->(ELBV2Listener)
    +```
    +
    +
    +
  • +
+
+
+
+

Ip

+

Represents a generic IP address.

+ ++++ + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

ip

The IPv4 address

id

Same as ip

+
+

Relationships

+
    +
  • DNSRecords can point to IP addresses.

    +
    ```
    +(DNSRecord)-[DNS_POINTS_TO]->(Ip)
    +```
    +
    +
    +
  • +
+
+
+
+

IpRule

+

Represents a generic IP rule. The creation of this node is currently derived from ingesting AWS EC2 Security Group rules.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

ruleid

{group_id}/{rule_type}/{from_port}{to_port}{protocol}

groupid

The groupid of the EC2 Security Group that this was derived from

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

protocol

The protocol this rule applies to

fromport

Lowest port in the range defined by this rule

toport

Highest port in the range defined by this rule

+
+

Relationships

+
    +
  • IpRules are defined from EC2SecurityGroups.

    +
    ```
    +(IpRule, IpPermissionInbound)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup)
    +```
    +
    +
    +
  • +
+
+
+
+

IpRule::IpPermissionInbound

+

An IpPermissionInbound node is a specific type of IpRule. It represents a generic inbound IP-based rules. The creation of this node is currently derived from ingesting AWS EC2 Security Group rules.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

ruleid

{group_id}/{rule_type}/{from_port}{to_port}{protocol}

groupid

The groupid of the EC2 Security Group that this was derived from

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

protocol

The protocol this rule applies to

fromport

Lowest port in the range defined by this rule

toport

Highest port in the range defined by this rule

+
+

Relationships

+
    +
  • IpPermissionInbound rules are defined from EC2SecurityGroups.

    +
    ```
    +(IpRule, IpPermissionInbound)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup)
    +```
    +
    +
    +
  • +
+
+
+
+

LoadBalancer

+

Represents an AWS Elastic Load Balancer. See spec for details.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

scheme

The type of load balancer. Valid only for load balancers in a VPC. If scheme is internet-facing, the load balancer has a public DNS name that resolves to a public IP address. If scheme is internal, the load balancer has a public DNS name that resolves to a private IP address.

name

The name of the load balancer

dnsname

The DNS name of the load balancer.

canonicalhostedzonename

The DNS name of the load balancer

id

Currently set to the dnsname of the load balancer.

region

The region of the load balancer

createdtime

The date and time the load balancer was created.

canonicalhostedzonenameid

The ID of the Amazon Route 53 hosted zone for the load balancer.

exposed_internet

The exposed_internet flag is set to True when the load balancer’s scheme field is set to internet-facing. This indicates that the load balancer has a public DNS name that resolves to a public IP address.

+
+

Relationships

+
    +
  • LoadBalancers can be connected to EC2Instances and therefore expose them.

    +
    ```
    +(LoadBalancer)-[EXPOSE]->(EC2Instance)
    +```
    +
    +
    +
  • +
  • LoadBalancers can have source security groups configured.

    +
    ```
    +(LoadBalancer)-[SOURCE_SECURITY_GROUP]->(EC2SecurityGroup)
    +```
    +
    +
    +
  • +
  • LoadBalancers can be part of EC2SecurityGroups.

    +
    ```
    +(LoadBalancer)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup)
    +```
    +
    +
    +
  • +
  • LoadBalancers can be part of EC2 Subnets

    +
    ```
    +(LoadBalancer)-[SUBNET]->(EC2Subnet)
    +```
    +
    +
    +
  • +
  • LoadBalancers can be part of EC2 Subnets

    +
    ```
    +(LoadBalancer)-[PART_OF_SUBNET]->(EC2Subnet)
    +```
    +
    +
    +
  • +
  • LoadBalancers can have listeners configured to accept connections from clients (good introduction).

    +
    ```
    +(LoadBalancer)-[ELB_LISTENER]->(Endpoint, ELBListener)
    +```
    +
    +
    +
  • +
  • LoadBalancers are part of AWSAccounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(LoadBalancer)
    +```
    +
    +
    +
  • +
  • AWSDNSRecords and DNSRecords point to LoadBalancers.

    +
    ```
    +(AWSDNSRecord, DNSRecord)-[DNS_POINTS_TO]->(LoadBalancer)
    +```
    +
    +
    +
  • +
+
+
+
+

LoadBalancerV2

+

Represents an Elastic Load Balancer V2 (Application Load Balancer or Network Load Balancer.) API reference here.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

scheme

The type of load balancer. If scheme is internet-facing, the load balancer has a public DNS name that resolves to a public IP address. If scheme is internal, the load balancer has a public DNS name that resolves to a private IP address.

name

The name of the load balancer

dnsname

The DNS name of the load balancer.

exposed_internet

The exposed_internet flag is set to True when the load balancer’s scheme field is set to internet-facing. This indicates that the load balancer has a public DNS name that resolves to a public IP address.

id

Currently set to the dnsname of the load balancer.

type

Can be application or network

region

The region of the load balancer

createdtime

The date and time the load balancer was created.

canonicalhostedzonenameid

The ID of the Amazon Route 53 hosted zone for the load balancer.

+
+

Relationships

+
    +
  • LoadBalancerV2’s can be connected to EC2Instances and therefore expose them.

    +
    ```
    +(LoadBalancerV2)-[EXPOSE]->(EC2Instance)
    +```
    +
    +
    +
  • +
  • LoadBalancerV2’s can be part of EC2SecurityGroups but only if their type = “application”. NLBs don’t have SGs.

    +
    ```
    +(LoadBalancerV2)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup)
    +```
    +
    +
    +
  • +
  • LoadBalancerV2’s can be part of EC2 Subnets

    +
    ```
    +(LoadBalancerV2)-[SUBNET]->(EC2Subnet)
    +```
    +
    +
    +
  • +
  • LoadBalancerV2’s can be part of EC2 Subnets

    +
    ```
    +(LoadBalancerV2)-[PART_OF_SUBNET]->(EC2Subnet)
    +```
    +
    +
    +
  • +
  • LoadBalancerV2’s have listeners:

    +
    ```
    +(LoadBalancerV2)-[ELBV2_LISTENER]->(ELBV2Listener)
    +```
    +
    +
    +
  • +
+
+
+
+

Nameserver

+

Represents a DNS nameserver. +| Field | Description | +|-------|————-| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The address of the nameserver| +| name | The name or address of the nameserver|

+
+

Relationships

+
    +
  • Nameservers are nameservers for to DNSZone.

    +
    ```
    +(Nameserver)-[NAMESERVER]->(DNSZone)
    +```
    +
    +
    +
  • +
+
+
+
+

NetworkInterface

+

Representation of a generic Network Interface. Currently however, we only create NetworkInterface nodes from AWS EC2 Instances. The spec for an AWS EC2 network interface is here.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

mac_address

The MAC address of the network interface

description

Description of the network interface

private_ip_address

The primary IPv4 address of the network interface within the subnet

id

The ID of the network interface. (known as networkInterfaceId in EC2)

private_dns_name

The private DNS name

status

Status of the network interface. Valid Values: available | associated | attaching | in-use | detaching

subnetid

The ID of the subnet

interface_type

Describes the type of network interface. Valid values: interface | efa

requester_id

Id of the requester, e.g. amazon-elb for ELBs

requester_managed

Indicates whether the interface is managed by the requester

source_dest_check

Indicates whether to validate network traffic to or from this network interface.

public_ip

Public IPv4 address attached to the interface

+
+

Relationships

+
    +
  • EC2 Network Interfaces belong to AWS accounts.

    +
    (NetworkInterface)<-[:RESOURCE]->(:AWSAccount)
    +
    +
    +
  • +
  • Network interfaces can be connected to EC2Subnets.

    +
    ```
    +(NetworkInterface)-[PART_OF_SUBNET]->(EC2Subnet)
    +```
    +
    +
    +
  • +
  • Network interfaces can be members of EC2SecurityGroups.

    +
    ```
    +(NetworkInterface)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup)
    +```
    +
    +
    +
  • +
  • EC2Instances can have NetworkInterfaces connected to them.

    +
    ```
    +(EC2Instance)-[NETWORK_INTERFACE]->(NetworkInterface)
    +```
    +
    +
    +
  • +
  • LoadBalancers can have NetworkInterfaces connected to them.

    +
    ```
    +(LoadBalancer)-[NETWORK_INTERFACE]->(NetworkInterface)
    +```
    +
    +
    +
  • +
  • LoadBalancerV2s can have NetworkInterfaces connected to them.

    +
    ```
    +(LoadBalancerV2)-[NETWORK_INTERFACE]->(NetworkInterface)
    +```
    +
    +
    +
  • +
  • EC2PrivateIps are connected to a NetworkInterface.

    +
    ```
    +(NetworkInterface)-[PRIVATE_IP_ADDRESS]->(EC2PrivateIp)
    +```
    +
    +
    +
  • +
  • EC2 Network Interfaces can be tagged with AWSTags.

    +
    ```
    +(NetworkInterface)-[TAGGED]->(AWSTag)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSPeeringConnection

+

Representation of an AWS PeeringConnection implementing an AWS VpcPeeringConnection object.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

vpcPeeringConnectionId, The ID of the VPC peering connection.

allow_dns_resolution_from_remote_vpc

Indicates whether a local VPC can resolve public DNS hostnames to private IP addresses when queried from instances in a peer VPC.

allow_egress_from_local_classic_link_to_remote_vpc

Indicates whether a local ClassicLink connection can communicate with the peer VPC over the VPC peering connection.

allow_egress_from_local_vpc_to_remote_classic_link

Indicates whether a local VPC can communicate with a ClassicLink connection in the peer VPC over the VPC peering connection.

requester_region

Peering requester region

accepter_region

Peering accepter region

status_code

The status of the VPC peering connection.

status_message

A message that provides more information about the status, if applicable.

+
+

Relationships

+
    +
  • AWSVpc is an accepter or requester vpc.

    +
    (AWSVpc)<-[REQUESTER_VPC]-(AWSPeeringConnection)
    +(AWSVpc)<-[ACCEPTER_VPC]-(AWSPeeringConnection)
    +
    +
    +
  • +
  • AWSCidrBlock is an accepter or requester cidr.

    +
    (AWSCidrBlock)<-[REQUESTER_CIDR]-(AWSPeeringConnection)
    +(AWSCidrBlock)<-[ACCEPTER_CIDR]-(AWSPeeringConnection)
    +
    +
    +
  • +
+
+
+
+

RedshiftCluster

+

Representation of an AWS RedshiftCluster.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

arn

The Amazon Resource Name (ARN) for the Redshift cluster

id

Same as arn

availability_zone

Specifies the name of the Availability Zone the cluster is located in

cluster_create_time

Provides the date and time the cluster was created

cluster_identifier

The unique identifier of the cluster.

cluster_revision_number

The specific revision number of the database in the cluster.

db_name

The name of the initial database that was created when the cluster was created. This same name is returned for the life of the cluster. If an initial database was not specified, a database named devdev was created by default.

encrypted

Specifies whether the cluster has encryption enabled

cluster_status

The current state of the cluster.

endpoint_address

DNS name of the Redshift cluster endpoint

endpoint_port

The port that the Redshift cluster’s endpoint is listening on

master_username

The master user name for the cluster. This name is used to connect to the database that is specified in the DBName parameter.

node_type

The node type for the nodes in the cluster.

number_of_nodes

The number of compute nodes in the cluster.

publicly_accessible

A boolean value that, if true, indicates that the cluster can be accessed from a public network.

vpc_id

The identifier of the VPC the cluster is in, if the cluster is in a VPC.

+
+

Relationships

+
    +
  • Redshift clusters are part of AWS Accounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(RedshiftCluster)
    +```
    +
    +
    +
  • +
  • Redshift clusters can be members of EC2 Security Groups.

    +
    (RedshiftCluster)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup)
    +
    +
    +
  • +
  • Redshift clusters may assume IAM roles. See this article.

    +
    (RedshiftCluster)-[STS_ASSUMEROLE_ALLOW]->(AWSPrincipal)
    +
    +
    +
  • +
  • Redshift clusters can be members of AWSVpcs.

    +
    (RedshiftCluster)-[MEMBER_OF_AWS_VPC]->(AWSVpc)
    +
    +
    +
  • +
+
+
+
+

RDSCluster

+

Representation of an AWS Relational Database Service DBCluster

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Same as ARN

arn

The Amazon Resource Name (ARN) for the DB cluster.

allocated_storage

For all database engines except Amazon Aurora, AllocatedStorage specifies the allocated storage size in gibibytes (GiB). For Aurora, AllocatedStorage always returns 1, because Aurora DB cluster storage size isn’t fixed, but instead automatically adjusts as needed.

availability_zones

Provides the list of Availability Zones (AZs) where instances in the DB cluster can be created.

backup_retention_period

Specifies the number of days for which automatic DB snapshots are retained.

character_set_name

If present, specifies the name of the character set that this cluster is associated with.

database_name

Contains the name of the initial database of this DB cluster that was provided at create time, if one was specified when the DB cluster was created. This same name is returned for the life of the DB cluster.

db_cluster_identifier

Contains a user-supplied DB cluster identifier. This identifier is the unique key that identifies a DB cluster.

db_parameter_group

Specifies the name of the DB cluster parameter group for the DB cluster.

status

Specifies the current state of this DB cluster.

earliest_restorable_time

The earliest time to which a database can be restored with point-in-time restore.

endpoint

Specifies the connection endpoint for the primary instance of the DB cluster.

reader_endpoint

The reader endpoint for the DB cluster. The reader endpoint for a DB cluster load-balances connections across the Aurora Replicas that are available in a DB cluster. As clients request new connections to the reader endpoint, Aurora distributes the connection requests among the Aurora Replicas in the DB cluster. This functionality can help balance your read workload across multiple Aurora Replicas in your DB cluster. If a failover occurs, and the Aurora Replica that you are connected to is promoted to be the primary instance, your connection is dropped. To continue sending your read workload to other Aurora Replicas in the cluster, you can then reconnect to the reader endpoint.

multi_az

Specifies whether the DB cluster has instances in multiple Availability Zones.

engine

The name of the database engine to be used for this DB cluster.

engine_version

Indicates the database engine version.

latest_restorable_time

Specifies the latest time to which a database can be restored with point-in-time restore.

port

Specifies the port that the database engine is listening on.

master_username

Contains the master username for the DB cluster.

preferred_backup_window

Specifies the daily time range during which automated backups are created if automated backups are enabled, as determined by the BackupRetentionPeriod.

preferred_maintenance_window

Specifies the weekly time range during which system maintenance can occur, in Universal Coordinated Time (UTC).

hosted_zone_id

Specifies the ID that Amazon Route 53 assigns when you create a hosted zone.

storage_encrypted

Specifies whether the DB cluster is encrypted.

kms_key_id

If StorageEncrypted is enabled, the AWS KMS key identifier for the encrypted DB cluster. The AWS KMS key identifier is the key ARN, key ID, alias ARN, or alias name for the AWS KMS customer master key (CMK).

db_cluster_resource_id

The AWS Region-unique, immutable identifier for the DB cluster. This identifier is found in AWS CloudTrail log entries whenever the AWS KMS CMK for the DB cluster is accessed.

clone_group_id

Identifies the clone group to which the DB cluster is associated.

cluster_create_time

Specifies the time when the DB cluster was created, in Universal Coordinated Time (UTC).

earliest_backtrack_time

The earliest time to which a DB cluster can be backtracked.

backtrack_window

The target backtrack window, in seconds. If this value is set to 0, backtracking is disabled for the DB cluster. Otherwise, backtracking is enabled.

backtrack_consumed_change_records

The number of change records stored for Backtrack.

capacity

The current capacity of an Aurora Serverless DB cluster. The capacity is 0 (zero) when the cluster is paused.

engine_mode

The DB engine mode of the DB cluster, either provisioned, serverless, parallelquery, global, or multimaster.

scaling_configuration_info_min_capacity

The minimum capacity for the Aurora DB cluster in serverless DB engine mode.

scaling_configuration_info_max_capacity

The maximum capacity for an Aurora DB cluster in serverless DB engine mode.

scaling_configuration_info_auto_pause

A value that indicates whether automatic pause is allowed for the Aurora DB cluster in serverless DB engine mode.

deletion_protection

Indicates if the DB cluster has deletion protection enabled. The database can’t be deleted when deletion protection is enabled.

+
+

Relationships

+
    +
  • RDS Clusters are part of AWS Accounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(RDSCluster)
    +```
    +
    +
    +
  • +
  • Some RDS instances are cluster members.

    +
    (replica:RDSInstance)-[IS_CLUSTER_MEMBER_OF]->(source:RDSCluster)
    +
    +
    +
  • +
+
+
+
+

RDSInstance

+

Representation of an AWS Relational Database Service DBInstance.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Same as ARN

arn

The Amazon Resource Name (ARN) for the DB instance.

db_instance_identifier

Contains a user-supplied database identifier. This identifier is the unique key that identifies a DB instance.

availability_zone

Specifies the name of the Availability Zone the DB instance is located in.

backup_retention_period

Specifies the number of days for which automatic DB snapshots are retained.

preferred_backup_window

Specifies the daily time range during which automated backups are created if automated backups are enabled, as determined by the BackupRetentionPeriod.

ca_certificate_identifier

The identifier of the CA certificate for this DB instance.

db_cluster_identifier

If the DB instance is a member of a DB cluster, contains the name of the DB cluster that the DB instance is a member of.

db_instance_class

Contains the name of the compute and memory capacity class of the DB instance.

db_instance_port

Specifies the port that the DB instance listens on.

dbi_resource_id

The AWS Region-unique, immutable identifier for the DB instance. This identifier is found in AWS CloudTrail log entries whenever the AWS KMS key for the DB instance is accessed.

db_name

The meaning of this parameter differs according to the database engine you use. For example, this value returns MySQL, MariaDB, or PostgreSQL information when returning values from CreateDBInstanceReadReplica since Read Replicas are only supported for these engines.

MySQL, MariaDB, SQL Server, PostgreSQL: Contains the name of the initial database of this instance that was provided at create time, if one was specified when the DB instance was created. This same name is returned for the life of the DB instance.

Oracle: Contains the Oracle System ID (SID) of the created DB instance. Not shown when the returned parameters do not apply to an Oracle DB instance.

engine

Provides the name of the database engine to be used for this DB instance.

engine_version

Indicates the database engine version.

enhanced_monitoring_resource_arn

The Amazon Resource Name (ARN) of the Amazon CloudWatch Logs log stream that receives the Enhanced Monitoring metrics data for the DB instance.

instance_create_time

Provides the date and time the DB instance was created.

kms_key_id

If StorageEncrypted is true, the AWS KMS key identifier for the encrypted DB instance.

master_username

Contains the master username for the DB instance.

monitoring_role_arn

The ARN for the IAM role that permits RDS to send Enhanced Monitoring metrics to Amazon CloudWatch Logs.

multi_az

Specifies if the DB instance is a Multi-AZ deployment.

performance_insights_enabled

True if Performance Insights is enabled for the DB instance, and otherwise false.

preferred_maintenance_window

Specifies the weekly time range during which system maintenance can occur, in Universal Coordinated Time (UTC).

publicly_accessible

Specifies the accessibility options for the DB instance. A value of true specifies an Internet-facing instance with a publicly resolvable DNS name, which resolves to a public IP address. A value of false specifies an internal instance with a DNS name that resolves to a private IP address.

storage_encrypted

Specifies whether the DB instance is encrypted.

endpoint_address

DNS name of the RDS instance

endpoint_port

The port that the RDS instance is listening on

endpoint_hostedzoneid

The AWS DNS Zone ID that is associated with the RDS instance’s DNS entry

auto_minor_version_upgrade

Specifies whether minor version upgrades are applied automatically to the DB instance during the maintenance window

iam_database_authentication_enabled

Specifies if mapping of AWS Identity and Access Management (IAM) accounts to database accounts is enabled

+
+

Relationships

+
    +
  • RDS Instances are part of AWS Accounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(RDSInstance)
    +```
    +
    +
    +
  • +
  • Some RDS instances are Read Replicas.

    +
    (replica:RDSInstance)-[IS_READ_REPLICA_OF]->(source:RDSInstance)
    +
    +
    +
  • +
  • RDS Instances can be members of EC2 Security Groups.

    +
    (RDSInstance)-[m:MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup)
    +
    +
    +
  • +
  • RDS Instances are connected to DB Subnet Groups.

    +
    (RDSInstance)-[:MEMBER_OF_DB_SUBNET_GROUP]->(DBSubnetGroup)
    +
    +
    +
  • +
  • RDS Instances can be tagged with AWSTags.

    +
    ```
    +(RDSInstance)-[TAGGED]->(AWSTag)
    +```
    +
    +
    +
  • +
+
+
+
+

RDSSnapshot

+

Representation of an AWS Relational Database Service DBSnapshot.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Same as ARN

arn

The Amazon Resource Name (ARN) for the DB snapshot.

db_snapshot_identifier

Specifies the identifier for the DB snapshot.

db_instance_identifier

Specifies the DB instance identifier of the DB instance this DB snapshot was created from.

snapshot_create_time

Specifies when the snapshot was taken in Coordinated Universal Time (UTC). Changes for the copy when the snapshot is copied.

engine

Specifies the name of the database engine.

allocated_storage

Specifies the allocated storage size in gibibytes (GiB).

status

Specifies the status of this DB snapshot.

port

Specifies the port that the database engine was listening on at the time of the snapshot.

availability_zone

Specifies the name of the Availability Zone the DB instance was located in at the time of the DB snapshot.

vpc_id

Provides the VPC ID associated with the DB snapshot.

instance_create_time

Specifies the time in Coordinated Universal Time (UTC) when the DB instance, from which the snapshot was taken, was created.

master_username

Provides the master username for the DB snapshot.

engine_version

Specifies the version of the database engine.

license_model

License model information for the restored DB instance.

snapshot_type

Provides the type of the DB snapshot.

iops

Specifies the Provisioned IOPS (I/O operations per second) value of the DB instance at the time of the snapshot.

option_group_name

Provides the option group name for the DB snapshot.

percent_progress

The percentage of the estimated data that has been transferred.

source_region

The AWS Region that the DB snapshot was created in or copied from.

source_db_snapshot_identifier

The DB snapshot Amazon Resource Name (ARN) that the DB snapshot was copied from. It only has a value in the case of a cross-account or cross-Region copy.

storage_type

Specifies the storage type associated with DB snapshot.

tde_credential_arn

The ARN from the key store with which to associate the instance for TDE encryption.

encrypted

Specifies whether the DB snapshot is encrypted.

kms_key_id

If Encrypted is true, the AWS KMS key identifier for the encrypted DB snapshot. The AWS KMS key identifier is the key ARN, key ID, alias ARN, or alias name for the KMS key.

timezone

The time zone of the DB snapshot. In most cases, the Timezone element is empty. Timezone content appears only for snapshots taken from Microsoft SQL Server DB instances that were created with a time zone specified.

iam_database_authentication_enabled

True if mapping of AWS Identity and Access Management (IAM) accounts to database accounts is enabled, and otherwise false.

processor_features

The number of CPU cores and the number of threads per core for the DB instance class of the DB instance when the DB snapshot was created.

dbi_resource_id

The identifier for the source DB instance, which can’t be changed and which is unique to an AWS Region.

original_snapshot_create_time

Specifies the time of the CreateDBSnapshot operation in Coordinated Universal Time (UTC). Doesn’t change when the snapshot is copied.

snapshot_database_time

The timestamp of the most recent transaction applied to the database that you’re backing up. Thus, if you restore a snapshot, SnapshotDatabaseTime is the most recent transaction in the restored DB instance. In contrast, originalSnapshotCreateTime specifies the system time that the snapshot completed. If you back up a read replica, you can determine the replica lag by comparing SnapshotDatabaseTime with originalSnapshotCreateTime. For example, if originalSnapshotCreateTime is two hours later than SnapshotDatabaseTime, then the replica lag is two hours.

snapshot_target

Specifies where manual snapshots are stored: AWS Outposts or the AWS Region.

storage_throughput

region

The AWS region of the snapshot

+
+

Relationships

+
    +
  • RDS Snapshots are part of AWS Accounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(RDSSnapshot)
    +```
    +
    +
    +
  • +
  • RDS Snapshots are connected to DB Instances.

    +
    (RDSSnapshot)-[:IS_SNAPSHOT_SOURCE]->(RDSInstance)
    +
    +
    +
  • +
  • RDS Snapshots can be tagged with AWSTags.

    +
    ```
    +(RDSSnapshot)-[TAGGED]->(AWSTag)
    +```
    +
    +
    +
  • +
+
+
+
+

S3Acl

+

Representation of an AWS S3 Access Control List.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

granteeid

The ID of the grantee as defined here

displayname

Optional display name for the ACL

permission

Valid values: FULL_CONTROL | READ | WRITE | READ_ACP | WRITE_ACP (ACP = Access Control Policy)

id

The ID of this ACL

type

The type of the grantee. Either CanonicalUser | AmazonCustomerByEmail | Group.

ownerid

The ACL’s owner ID as defined here

+
+

Relationships

+
    +
  • S3 Access Control Lists apply to S3 buckets.

    +
    ```
    +(S3Acl)-[APPLIES_TO]->(S3Bucket)
    +```
    +
    +
    +
  • +
+
+
+
+

S3Bucket

+

Representation of an AWS S3 Bucket.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

creationdate

Date-time when the bucket was created

id

Same as name, as seen below

name

The name of the bucket. This is guaranteed to be globally unique

anonymous_actions

List of anonymous internet accessible actions that may be run on the bucket. This list is taken by running policyuniverse on the policy that applies to the bucket.

anonymous_access

True if this bucket has a policy applied to it that allows anonymous access or if it is open to the internet. These policy determinations are made by using the policyuniverse library.

region

The region that the bucket is in. Only defined if the S3 bucket has a location constraint

default_encryption

True if this bucket has default encryption enabled.

encryption_algorithm

The encryption algorithm used for default encryption. Only defined if the S3 bucket has default encryption enabled.

encryption_key_id

The KMS key ID used for default encryption. Only defined if the S3 bucket has SSE-KMS enabled as the default encryption method.

bucket_key_enabled

True if a bucket key is enabled, when using SSE-KMS as the default encryption method.

versioning_status

The versioning state of the bucket.

mfa_delete

Specifies whether MFA delete is enabled in the bucket versioning configuration.

block_public_acls

Specifies whether Amazon S3 should block public access control lists (ACLs) for this bucket and objects in this bucket.

ignore_public_acls

Specifies whether Amazon S3 should ignore public ACLs for this bucket and objects in this bucket.

block_public_acls

Specifies whether Amazon S3 should block public bucket policies for this bucket.

restrict_public_buckets

Specifies whether Amazon S3 should restrict public bucket policies for this bucket.

+
+

Relationships

+
    +
  • S3Buckets are resources in an AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(S3Bucket)
    +```
    +
    +
    +
  • +
  • S3 Access Control Lists apply to S3 buckets.

    +
    ```
    +(S3Acl)-[APPLIES_TO]->(S3Bucket)
    +```
    +
    +
    +
  • +
  • S3 Buckets can be tagged with AWSTags.

    +
    ```
    +(S3Bucket)-[TAGGED]->(AWSTag)
    +```
    +
    +
    +
  • +
+
+
+
+

S3PolicyStatement

+

Representation of an AWS S3 Bucket Policy Statements for controlling ownership of objects and ACLs of the bucket.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

policy_id

Optional string “Id” for the bucket’s policy

policy_version

Version of the bucket’s policy

id

The unique identifier for a bucket policy statement.
If the statement has an Sid the id will be calculated as S3Bucket.id/policy_statement/index of statement in statement/Sid.
If the statement has no Sid the id will be calculated as S3Bucket.id/policy_statement/index of statement in statement/

effect

Specifies “Deny” or “Allow” for the policy statement

action

Specifies permissions that policy statement applies to, as defined here

resource

Specifies the resource the bucket policy statement is based on

condition

Specifies conditions where permissions are granted: examples

sid

Optional string to label the specific bucket policy statement

+
+

Relationships

+
    +
  • S3PolicyStatements define the policy for S3 Buckets.

    +
    ```
    +(:S3Bucket)-[:POLICY_STATEMENT]->(:S3PolicyStatement)
    +```
    +
    +
    +
  • +
+
+
+
+

KMSKey

+

Representation of an AWS KMS Key.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The id of the key

name

The name of the key

description

The description of the key

enabled

Whether the key is enabled

region

The region where key is created

anonymous_actions

List of anonymous internet accessible actions that may be run on the key.

anonymous_access

True if this key has a policy applied to it that allows anonymous access or if it is open to the internet.

+
+

Relationships

+
    +
  • AWS KMS Keys are resources in an AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(KMSKey)
    +```
    +
    +
    +
  • +
  • AWS KMS Key may also be refered as KMSAlias via aliases.

    +
    ```
    +(KMSKey)-[KNOWN_AS]->(KMSAlias)
    +```
    +
    +
    +
  • +
  • AWS KMS Key may also have KMSGrant based on grants.

    +
    ```
    +(KMSGrant)-[APPLIED_ON]->(KMSKey)
    +```
    +
    +
    +
  • +
+
+
+
+

KMSAlias

+

Representation of an AWS KMS Key Alias.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The arn of the alias

aliasname

The name of the alias

targetkeyid

The kms key id associated via this alias

+
+

Relationships

+
    +
  • AWS KMS Key may also be refered as KMSAlias via aliases.

    +
    ```
    +(KMSKey)-[KNOWN_AS]->(KMSAlias)
    +```
    +
    +
    +
  • +
+
+
+
+

KMSGrant

+

Representation of an AWS KMS Key Grant.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The id of the key grant

name

The name of the key grant

granteeprincipal

The principal associated with the key grant

creationdate

ISO 8601 date-time string when the grant was created

+
+

Relationships

+
    +
  • AWS KMS Key may also have KMSGrant based on grants.

    +
    ```
    +(KMSGrant)-[APPLIED_ON]->(KMSKey)
    +```
    +
    +
    +
  • +
+
+
+
+

APIGatewayRestAPI

+

Representation of an AWS API Gateway REST API.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The id of the REST API

createddate

The timestamp when the REST API was created

version

The version identifier for the API

minimumcompressionsize

A nullable integer that is used to enable or disable the compression of the REST API

disableexecuteapiendpoint

Specifies whether clients can invoke your API by using the default execute-api endpoint

region

The region where the REST API is created

anonymous_actions

List of anonymous internet accessible actions that may be run on the API.

anonymous_access

True if this API has a policy applied to it that allows anonymous access or if it is open to the internet.

+
+

Relationships

+
    +
  • AWS API Gateway REST APIs are resources in an AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(APIGatewayRestAPI)
    +```
    +
    +
    +
  • +
  • AWS API Gateway REST APIs may be associated with an API Gateway Stage.

    +
    ```
    +(APIGatewayRestAPI)-[ASSOCIATED_WITH]->(APIGatewayStage)
    +```
    +
    +
    +
  • +
  • AWS API Gateway REST APIs may also have API Gateway Resource resources.

    +
    ```
    +(APIGatewayRestAPI)-[RESOURCE]->(APIGatewayResource)
    +```
    +
    +
    +
  • +
+
+
+
+

APIGatewayStage

+

Representation of an AWS API Gateway Stage.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The name of the API Gateway Stage

createddate

The timestamp when the stage was created

deploymentid

The identifier of the Deployment that the stage points to.

clientcertificateid

The identifier of a client certificate for an API stage.

cacheclusterenabled

Specifies whether a cache cluster is enabled for the stage.

cacheclusterstatus

The status of the cache cluster for the stage, if enabled.

tracingenabled

Specifies whether active tracing with X-ray is enabled for the Stage

webaclarn

The ARN of the WebAcl associated with the Stage

+
+

Relationships

+
    +
  • AWS API Gateway REST APIs may be associated with an API Gateway Stage.

    +
    ```
    +(APIGatewayRestAPI)-[ASSOCIATED_WITH]->(APIGatewayStage)
    +```
    +
    +
    +
  • +
  • AWS API Gateway Stage may also contain a Client Certificate.

    +
    ```
    +(APIGatewayStage)-[HAS_CERTIFICATE]->(APIGatewayClientCertificate)
    +```
    +
    +
    +
  • +
+
+
+
+

APIGatewayClientCertificate

+

Representation of an AWS API Gateway Client Certificate.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The identifier of the client certificate

createddate

The timestamp when the client certificate was created

expirationdate

The timestamp when the client certificate will expire

+
+

Relationships

+
    +
  • AWS API Gateway Stage may also contain a Client Certificate.

    +
    ```
    +(APIGatewayStage)-[HAS_CERTIFICATE]->(APIGatewayClientCertificate)
    +```
    +
    +
    +
  • +
+
+
+
+

APIGatewayResource

+

Representation of an AWS API Gateway Resource.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The id of the REST API

path

The timestamp when the REST API was created

pathpart

The version identifier for the API

parentid

A nullable integer that is used to enable or disable the compression of the REST API

+
+

Relationships

+
    +
  • AWS API Gateway REST APIs may also have API Gateway Resource resources.

    +
    ```
    +(APIGatewayRestAPI)-[RESOURCE]->(APIGatewayResource)
    +```
    +
    +
    +
  • +
+
+
+
+

AutoScalingGroup

+

Representation of an AWS Auto Scaling Group Resource.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

arn

The ARN of the Auto Scaling Group

name

The name of the Auto Scaling group.

createdtime

The date and time the group was created.

launchconfigurationname

The name of the associated launch configuration.

launchtemplatename

The name of the launch template.

launchtemplateid

The ID of the launch template.

launchtemplateversion

The version number of the launch template.

maxsize

The maximum size of the group.

minsize

The minimum size of the group.

defaultcooldown

The duration of the default cooldown period, in seconds.

desiredcapacity

The desired size of the group.

healthchecktype

The service to use for the health checks.

healthcheckgraceperiod

The amount of time, in seconds, that Amazon EC2 Auto Scaling waits before checking the health status of an EC2 instance that has come into service.

status

The current state of the group when the DeleteAutoScalingGroup operation is in progress.

newinstancesprotectedfromscalein

Indicates whether newly launched instances are protected from termination by Amazon EC2 Auto Scaling when scaling in.

maxinstancelifetime

The maximum amount of time, in seconds, that an instance can be in service.

capacityrebalance

Indicates whether Capacity Rebalancing is enabled.

region

The region of the auto scaling group.

+

Link to API Documentation of AWS Auto Scaling Groups

+
+

Relationships

+
    +
  • AWS Auto Scaling Groups are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AutoScalingGroup)
    +```
    +
    +
    +
  • +
  • AWS Auto Scaling Groups has one or more subnets/vpc identifiers.

    +
    ```
    +(AutoScalingGroup)-[VPC_IDENTIFIER]->(EC2Subnet)
    +```
    +
    +
    +
  • +
  • AWS EC2 Instances are members of one or more AWS Auto Scaling Groups.

    +
    ```
    +(EC2Instance)-[MEMBER_AUTO_SCALE_GROUP]->(AutoScalingGroup)
    +```
    +
    +
    +
  • +
  • AWS Auto Scaling Groups have Launch Configurations

    +
    ```
    +(AutoScalingGroup)-[HAS_LAUNCH_CONFIG]->(LaunchConfiguration)
    +```
    +
    +
    +
  • +
  • AWS Auto Scaling Groups have Launch Templates

    +
    ```
    +(AutoScalingGroup)-[HAS_LAUNCH_TEMPLATE]->(LaunchTemplate)
    +```
    +
    +
    +
  • +
+
+
+
+

EC2Image

+

Representation of an AWS EC2 Images (AMIs).

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the AMI.

name

The name of the AMI that was provided during image creation.

creationdate

The date and time the image was created.

architecture

The architecture of the image.

location

The location of the AMI.

type

The type of image.

ispublic

Indicates whether the image has public launch permissions.

platform

This value is set to windows for Windows AMIs; otherwise, it is blank.

usageoperation

The operation of the Amazon EC2 instance and the billing code that is associated with the AMI.

state

The current state of the AMI.

description

The description of the AMI that was provided during image creation.

enasupport

Specifies whether enhanced networking with ENA is enabled.

hypervisor

The hypervisor type of the image.

rootdevicename

The device name of the root device volume (for example, /dev/sda1 ).

rootdevicetype

The type of root device used by the AMI.

virtualizationtype

The type of virtualization of the AMI.

bootmode

The boot mode of the image.

region

The region of the image.

+

Link to API Documentation of EC2 Images

+
+

Relationships

+
    +
  • AWS EC2 Images (AMIs) are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(EC2Image)
    +```
    +
    +
    +
  • +
+
+
+
+

EC2ReservedInstance

+

Representation of an AWS EC2 Reserved Instance.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the Reserved Instance.

availabilityzone

The Availability Zone in which the Reserved Instance can be used.

duration

The duration of the Reserved Instance, in seconds.

end

The time when the Reserved Instance expires.

start

The date and time the Reserved Instance started.

count

The number of reservations purchased.

type

The instance type on which the Reserved Instance can be used.

productdescription

The Reserved Instance product platform description.

state

The state of the Reserved Instance purchase.

currencycode

The currency of the Reserved Instance. It’s specified using ISO 4217 standard currency codes.

instancetenancy

The tenancy of the instance.

offeringclass

The offering class of the Reserved Instance.

offeringtype

The Reserved Instance offering type.

scope

The scope of the Reserved Instance.

fixedprice

The purchase price of the Reserved Instance.

region

The region of the reserved instance.

+
+

Relationships

+
    +
  • AWS EC2 Reserved Instances are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(EC2ReservedInstance)
    +```
    +
    +
    +
  • +
+
+
+
+

SecretsManagerSecret

+

Representation of an AWS Secrets Manager Secret

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The arn of the secret.

created_date

The date and time when a secret was created.

deleted_date

The date and time the deletion of the secret occurred. Not present on active secrets. The secret can be recovered until the number of days in the recovery window has passed, as specified in the RecoveryWindowInDays parameter of the DeleteSecret operation.

description

The user-provided description of the secret.

kms_key_id

The ARN or alias of the AWS KMS customer master key (CMK) used to encrypt the SecretString and SecretBinary fields in each version of the secret. If you don’t provide a key, then Secrets Manager defaults to encrypting the secret fields with the default KMS CMK, the key named awssecretsmanager, for this account.

last_accessed_date

The last date that this secret was accessed. This value is truncated to midnight of the date and therefore shows only the date, not the time.

last_changed_date

The last date and time that this secret was modified in any way.

last_rotated_date

The most recent date and time that the Secrets Manager rotation process was successfully completed. This value is null if the secret hasn’t ever rotated.

name

The friendly name of the secret. You can use forward slashes in the name to represent a path hierarchy. For example, /prod/databases/dbserver1 could represent the secret for a server named dbserver1 in the folder databases in the folder prod.

owning_service

Returns the name of the service that created the secret.

primary_region

The Region where Secrets Manager originated the secret.

rotation_enabled

Indicates whether automatic, scheduled rotation is enabled for this secret.

rotation_lambda_arn

The ARN of an AWS Lambda function invoked by Secrets Manager to rotate and expire the secret either automatically per the schedule or manually by a call to RotateSecret.

rotation_rules_automatically_after_days

Specifies the number of days between automatic scheduled rotations of the secret.

+
+

Relationships

+
    +
  • AWS Secrets Manager Secrets are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(SecretsManagerSecret)
    +```
    +
    +
    +
  • +
+
+
+
+

EBSVolume

+

Representation of an AWS EBS Volume.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the EBS Volume.

availabilityzone

The Availability Zone for the volume.

createtime

The time stamp when volume creation was initiated.

encrypted

Indicates whether the volume is encrypted.

size

The size of the volume, in GiBs.

state

The volume state.

outpostarn

The Amazon Resource Name (ARN) of the Outpost.

snapshotid

The snapshot ID.

iops

The number of I/O operations per second (IOPS).

type

The volume type.

fastrestored

Indicates whether the volume was created using fast snapshot restore.

multiattachenabled

Indicates whether Amazon EBS Multi-Attach is enabled.

throughput

The throughput that the volume supports, in MiB/s.

kmskeyid

The Amazon Resource Name (ARN) of the AWS Key Management Service (AWS KMS) customer master key (CMK) that was used to protect the volume encryption key for the volume.

deleteontermination

Indicates whether the volume is deleted on instance termination.

region

The region of the volume.

+
+

Relationships

+
    +
  • AWS EBS Volumes are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(EBSVolume)
    +```
    +
    +
    +
  • +
  • AWS EBS Snapshots are created using EBS Volumes

    +
    ```
    +(EBSSnapshot)-[CREATED_FROM]->(EBSVolume)
    +```
    +
    +
    +
  • +
  • AWS EBS Volumes are attached to an EC2 Instance

    +
    ```
    +(EBSVolume)-[ATTACHED_TO_EC2_INSTANCE]->(EC2Instance)
    +```
    +
    +
    +
  • +
  • AWSTag

    +
    ```
    +(EBSVolume)-[TAGGED]->(AWSTag)
    +```
    +
    +
    +
  • +
+
+
+
+

EBSSnapshot

+

Representation of an AWS EBS Snapshot.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the EBS Snapshot.

description

The description of the snapshot.

progress

The progress of the snapshot, as a percentage.

encrypted

Indicates whether the snapshot is encrypted.

starttime

The time stamp when the snapshot was initiated.

state

The snapshot state.

statemessage

Encrypted Amazon EBS snapshots are copied asynchronously. If a snapshot copy operation fails (for example, if the proper AWS Key Management Service (AWS KMS) permissions are not obtained) this field displays error state details to help you diagnose why the error occurred. This parameter is only returned by DescribeSnapshots .

volumeid

The volume ID.

volumesize

The size of the volume, in GiB.

outpostarn

The ARN of the AWS Outpost on which the snapshot is stored.

dataencryptionkeyid

The data encryption key identifier for the snapshot.

kmskeyid

The Amazon Resource Name (ARN) of the AWS Key Management Service (AWS KMS) customer master key (CMK) that was used to protect the volume encryption key for the parent volume.

region

The region of the snapshot.

+
+

Relationships

+
    +
  • AWS EBS Snapshots are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(EBSSnapshot)
    +```
    +
    +
    +
  • +
  • AWS EBS Snapshots are created using EBS Volumes

    +
    ```
    +(EBSSnapshot)-[CREATED_FROM]->(EBSVolume)
    +```
    +
    +
    +
  • +
+
+
+
+

SQSQueue

+

Representation of an AWS SQS Queue

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The arn of the sqs queue.

created_timestamp

The time when the queue was created in seconds

delay_seconds

The default delay on the queue in seconds.

last_modified_timestamp

The time when the queue was last changed in seconds.

maximum_message_size

The limit of how many bytes a message can contain before Amazon SQS rejects it.

message_retention_period

he length of time, in seconds, for which Amazon SQS retains a message.

policy

The IAM policy of the queue.

arn

The arn of the sqs queue.

receive_message_wait_time_seconds

The length of time, in seconds, for which the ReceiveMessage action waits for a message to arrive.

redrive_policy_dead_letter_target_arn

The Amazon Resource Name (ARN) of the dead-letter queue to which Amazon SQS moves messages after the value of maxReceiveCount is exceeded.

redrive_policy_max_receive_count

The number of times a message is delivered to the source queue before being moved to the dead-letter queue. When the ReceiveCount for a message exceeds the maxReceiveCount for a queue, Amazon SQS moves the message to the dead-letter-queue.

visibility_timeout

The visibility timeout for the queue.

kms_master_key_id

The ID of an AWS managed customer master key (CMK) for Amazon SQS or a custom CMK.

kms_data_key_reuse_period_seconds

The length of time, in seconds, for which Amazon SQS can reuse a data key to encrypt or decrypt messages before calling AWS KMS again.

fifo_queue

Whether or not the queue is FIFO.

content_based_deduplication

Whether or not content-based deduplication is enabled for the queue.

deduplication_scope

Specifies whether message deduplication occurs at the message group or queue level.

fifo_throughput_limit

Specifies whether the FIFO queue throughput quota applies to the entire queue or per message group.

+
+

Relationships

+
    +
  • AWS SQS Queues are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(SQSQueue)
    +```
    +
    +
    +
  • +
  • AWS SQS Queues can have other SQS Queues configured as dead letter queues

    +
    ```
    +(SQSQueue)-[HAS_DEADLETTER_QUEUE]->(SQSQueue)
    +```
    +
    +
    +
  • +
+
+
+
+

SecurityHub

+

Representation of the configuration of AWS Security Hub

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The arn of the hub resource.

subscribed_at

The date and time when Security Hub was enabled in the account.

auto_enable_controls

Whether to automatically enable new controls when they are added to standards that are enabled.

+
+

Relationships

+
    +
  • AWS Security Hub nodes are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(SecurityHub)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSConfigurationRecorder

+

Representation of an AWS Config Configuration Recorder

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

A combination of name:account_id:region

name

The name of the recorder.

role_arn

Amazon Resource Name (ARN) of the IAM role used to describe the AWS resources associated with the account.

recording_group_all_supported

Specifies whether AWS Config records configuration changes for every supported type of regional resource.

recording_group_include_global_resource_types

Specifies whether AWS Config includes all supported types of global resources (for example, IAM resources) with the resources that it records.

recording_group_resource_types

A comma-separated list that specifies the types of AWS resources for which AWS Config records configuration changes (for example, AWS::EC2::Instance or AWS::CloudTrail::Trail).

region

The region of the configuration recorder.

+
+

Relationships

+
    +
  • AWS Configuration Recorders are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSConfigurationRecorder)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSConfigDeliveryChannel

+

Representation of an AWS Config Delivery Channel

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

A combination of name:account_id:region

name

The name of the delivery channel.

s3_bucket_name

The name of the Amazon S3 bucket to which AWS Config delivers configuration snapshots and configuration history files.

s3_key_prefix

The prefix for the specified Amazon S3 bucket.

s3_kms_key_arn

The Amazon Resource Name (ARN) of the AWS Key Management Service (KMS) customer managed key (CMK) used to encrypt objects delivered by AWS Config. Must belong to the same Region as the destination S3 bucket.

sns_topic_arn

The Amazon Resource Name (ARN) of the Amazon SNS topic to which AWS Config sends notifications about configuration changes.

config_snapshot_delivery_properties_delivery_frequency

The frequency with which AWS Config delivers configuration snapshots.

region

The region of the delivery channel.

+
+

Relationships

+
    +
  • AWS Config Delivery Channels are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSConfigDeliveryChannel)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSConfigRule

+

Representation of an AWS Config Rule

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ARN of the config rule.

name

The name of the delivery channel.

description

The description that you provide for the AWS Config rule.

arn

The ARN of the config rule.

rule_id

The ID of the AWS Config rule.

scope_compliance_resource_types

The resource types of only those AWS resources that you want to trigger an evaluation for the rule. You can only specify one type if you also specify a resource ID for ComplianceResourceId.

scope_tag_key

The tag key that is applied to only those AWS resources that you want to trigger an evaluation for the rule.

scope_tag_value

The tag value applied to only those AWS resources that you want to trigger an evaluation for the rule. If you specify a value for TagValue, you must also specify a value for TagKey.

scope_tag_compliance_resource_id

The resource types of only those AWS resources that you want to trigger an evaluation for the rule. You can only specify one type if you also specify a resource ID for ComplianceResourceId.

source_owner

Indicates whether AWS or the customer owns and manages the AWS Config rule.

source_identifier

For AWS Config managed rules, a predefined identifier from a list. For example, IAM_PASSWORD_POLICY is a managed rule.

source_details

Provides the source and type of the event that causes AWS Config to evaluate your AWS resources.

input_parameters

A string, in JSON format, that is passed to the AWS Config rule Lambda function.

maximum_execution_frequency

The maximum frequency with which AWS Config runs evaluations for a rule.

created_by

Service principal name of the service that created the rule.

region

The region of the delivery channel.

+
+

Relationships

+
    +
  • AWS Config Rules are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSConfigRule)
    +```
    +
    +
    +
  • +
+
+
+
+

LaunchConfiguration

+

Representation of an AWS Launch Configuration

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ARN of the launch configuration.

name

The name of the launch configuration.

arn

The ARN of the launch configuration.

created_time

The creation date and time for the launch configuration.

image_id

The ID of the Amazon Machine Image (AMI) to use to launch your EC2 instances.

key_name

The name of the key pair.

security_groups

A list that contains the security groups to assign to the instances in the Auto Scaling group.

instance_type

The instance type for the instances.

kernel_id

The ID of the kernel associated with the AMI.

ramdisk_id

The ID of the RAM disk associated with the AMI.

instance_monitoring_enabled

If true, detailed monitoring is enabled. Otherwise, basic monitoring is enabled.

spot_price

The maximum hourly price to be paid for any Spot Instance launched to fulfill the request.

iam_instance_profile

The name or the Amazon Resource Name (ARN) of the instance profile associated with the IAM role for the instance.

ebs_optimized

Specifies whether the launch configuration is optimized for EBS I/O (true) or not (false).

associate_public_ip_address

For Auto Scaling groups that are running in a VPC, specifies whether to assign a public IP address to the group’s instances.

placement_tenancy

The tenancy of the instance, either default or dedicated. An instance with dedicated tenancy runs on isolated, single-tenant hardware and can only be launched into a VPC.

region

The region of the launch configuration.

+
+

Relationships

+
    +
  • Launch Configurations are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(LaunchConfiguration)
    +```
    +
    +
    +
  • +
+
+
+
+

LaunchTemplate

+

Representation of an AWS Launch Template

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the launch template.

name

The name of the launch template.

create_time

The time launch template was created.

created_by

The principal that created the launch template.

default_version_number

The version number of the default version of the launch template.

latest_version_number

The version number of the latest version of the launch template.

region

The region of the launch template.

+
+

Relationships

+
    +
  • Launch Templates are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(LaunchTemplate)
    +```
    +
    +
    +
  • +
  • Launch templates have Launch Template Versions

    +
    ```
    +(LaunchTemplate)-[VERSION]->(LaunchTemplateVersion)
    +```
    +
    +
    +
  • +
+
+
+
+

LaunchTemplateVersion

+

Representation of an AWS Launch Template Version

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the launch template version (ID-version).

name

The name of the launch template.

create_time

The time the version was created.

created_by

The principal that created the version.

default_version

Indicates whether the version is the default version.

version_number

The version number.

version_description

The description of the version.

kernel_id

The ID of the kernel, if applicable.

ebs_optimized

Indicates whether the instance is optimized for Amazon EBS I/O.

iam_instance_profile_arn

The Amazon Resource Name (ARN) of the instance profile.

iam_instance_profile_name

The name of the instance profile.

image_id

The ID of the AMI that was used to launch the instance.

instance_type

The instance type.

key_name

The name of the key pair.

monitoring_enabled

Indicates whether detailed monitoring is enabled. Otherwise, basic monitoring is enabled.

ramdisk_id

The ID of the RAM disk, if applicable.

disable_api_termination

If set to true, indicates that the instance cannot be terminated using the Amazon EC2 console, command line tool, or API.

instance_initiated_shutdown_behavior

Indicates whether an instance stops or terminates when you initiate shutdown from the instance (using the operating system command for system shutdown).

security_group_ids

The security group IDs.

security_groups

The security group names.

region

The region of the launch template.

+
+

Relationships

+
    +
  • Launch Template Versions are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(LaunchTemplateVersion)
    +```
    +
    +
    +
  • +
+
+
+
+

ElasticIPAddress

+

Representation of an AWS EC2 Elastic IP address

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The Elastic IP address

instance_id

The ID of the instance that the address is associated with (if any).

public_ip

The Elastic IP address.

allocation_id

The ID representing the allocation of the address for use with EC2-VPC.

association_id

The ID representing the association of the address with an instance in a VPC.

domain

Indicates whether this Elastic IP address is for use with instances in EC2-Classic (standard) or instances in a VPC (vpc).

network_interface_id

The ID of the network interface.

private_ip_address

The private IP address associated with the Elastic IP address.

public_ipv4_pool

The ID of an address pool.

network_border_group

The name of the unique set of Availability Zones, Local Zones, or Wavelength Zones from which AWS advertises IP addresses.

customer_owned_ip

The customer-owned IP address.

customer_owned_ipv4_pool

The ID of the customer-owned address pool.

carrier_ip

The carrier IP address associated. This option is only available for network interfaces which reside in a subnet in a Wavelength Zone (for example an EC2 instance).

region

The region of the IP.

+
+

Relationships

+
    +
  • Elastic IPs are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(ElasticIPAddress)
    +```
    +
    +
    +
  • +
  • Elastic IPs can be attached to EC2 instances

    +
    ```
    +(EC2Instance)-[ELASTIC_IP_ADDRESS]->(ElasticIPAddress)
    +```
    +
    +
    +
  • +
  • Elastic IPs can be attached to NetworkInterfaces

    +
    ```
    +(NetworkInterface)-[ELASTIC_IP_ADDRESS]->(ElasticIPAddress)
    +```
    +
    +
    +
  • +
+
+
+
+

ECSCluster

+

Representation of an AWS ECS Cluster

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ARN of the cluster

region

The region of the cluster.

name

A user-generated string that you use to identify your cluster.

arn

The ARN of the cluster

ecc_kms_key_id

An AWS Key Management Service key ID to encrypt the data between the local client and the container.

ecc_logging

The log setting to use for redirecting logs for your execute command results.

ecc_log_configuration_cloud_watch_log_group_name

The name of the CloudWatch log group to send logs to.

ecc_log_configuration_cloud_watch_encryption_enabled

Determines whether to enable encryption on the CloudWatch logs.

ecc_log_configuration_s3_bucket_name

The name of the S3 bucket to send logs to.

ecc_log_configuration_s3_encryption_enabled

Determines whether to use encryption on the S3 logs.

ecc_log_configuration_s3_key_prefix

An optional folder in the S3 bucket to place logs in.

status

The status of the cluster

settings_container_insights

If enabled is specified, CloudWatch Container Insights will be enabled for the cluster, otherwise it will be disabled unless the containerInsights account setting is enabled.

capacity_providers

The capacity providers associated with the cluster.

attachments_status

The status of the capacity providers associated with the cluster.

+
+

Relationships

+
    +
  • ECSClusters are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(ECSCluster)
    +```
    +
    +
    +
  • +
+
+
+
+

ECSContainerInstance

+

Representation of an AWS ECS Container Instance

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ARN of the container instance

region

The region of the container instance.

ec2_instance_id

The ID of the container instance. For Amazon EC2 instances, this value is the Amazon EC2 instance ID. For external instances, this value is the AWS Systems Manager managed instance ID.

arn

The ARN of the container instance

capacity_provider_name

The capacity provider that’s associated with the container instance.

version

The version counter for the container instance.

version_info_agent_version

The version number of the Amazon ECS container agent.

version_info_agent_hash

The Git commit hash for the Amazon ECS container agent build on the amazon-ecs-agent GitHub repository.

version_info_agent_docker_version

The Docker version that’s running on the container instance.

status

The status of the container instance.

status_reason

The reason that the container instance reached its current status.

agent_connected

This parameter returns true if the agent is connected to Amazon ECS. Registered instances with an agent that may be unhealthy or stopped return false.

agent_update_status

The status of the most recent agent update. If an update wasn’t ever requested, this value is NULL.

registered_at

The Unix timestamp for the time when the container instance was registered.

+
+

Relationships

+
    +
  • An ECSCluster has ECSContainerInstances

    +
    ```
    +(ECSCluster)-[HAS_CONTAINER_INSTANCE]->(ECSContainerInstance)
    +```
    +
    +
    +
  • +
  • ECSContainerInstances have ECSTasks

    +
    ```
    +(ECSContainerInstance)-[HAS_TASK]->(ECSTask)
    +```
    +
    +
    +
  • +
+
+
+
+

ECSService

+

Representation of an AWS ECS Service

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ARN of the service

region

The region of the service.

name

The name of your service.

arn

The ARN of the service

cluster_arn

The Amazon Resource Name (ARN) of the cluster that hosts the service.

status

The status of the service.

desired_count

The desired number of instantiations of the task definition to keep running on the service.

running_count

The number of tasks in the cluster that are in the RUNNING state.

pending_count

The number of tasks in the cluster that are in the PENDING state.

launch_type

The launch type the service is using.

platform_version

The platform version to run your service on. A platform version is only specified for tasks that are hosted on AWS Fargate.

platform_family

The operating system that your tasks in the service run on. A platform family is specified only for tasks using the Fargate launch type.

task_definition

The task definition to use for tasks in the service.

deployment_config_circuit_breaker_enable

Determines whether to enable the deployment circuit breaker logic for the service.

deployment_config_circuit_breaker_rollback

Determines whether to enable Amazon ECS to roll back the service if a service deployment fails.

deployment_config_maximum_percent

If a service is using the rolling update (ECS) deployment type, the maximum percent parameter represents an upper limit on the number of tasks in a service that are allowed in the RUNNING or PENDING state during a deployment, as a percentage of the desired number of tasks (rounded down to the nearest integer), and while any container instances are in the DRAINING state if the service contains tasks using the EC2 launch type.

deployment_config_minimum_healthy_percent

If a service is using the rolling update (ECS) deployment type, the minimum healthy percent represents a lower limit on the number of tasks in a service that must remain in the RUNNING state during a deployment, as a percentage of the desired number of tasks (rounded up to the nearest integer), and while any container instances are in the DRAINING state if the service contains tasks using the EC2 launch type.

role_arn

The ARN of the IAM role that’s associated with the service.

created_at

The Unix timestamp for the time when the service was created.

health_check_grace_period_seconds

The period of time, in seconds, that the Amazon ECS service scheduler ignores unhealthy Elastic Load Balancing target health checks after a task has first started.

created_by

The principal that created the service.

enable_ecs_managed_tags

Determines whether to enable Amazon ECS managed tags for the tasks in the service.

propagate_tags

Determines whether to propagate the tags from the task definition or the service to the task.

enable_execute_command

Determines whether the execute command functionality is enabled for the service.

+
+

Relationships

+
    +
  • An ECSCluster has ECSService

    +
    ```
    +(ECSCluster)-[HAS_SERVICE]->(ECSService)
    +```
    +
    +
    +
  • +
  • An ECSCluster has ECSContainerInstances

    +
    ```
    +(ECSCluster)-[HAS_CONTAINER_INSTANCE]->(ECSContainerInstance)
    +```
    +
    +
    +
  • +
+
+
+
+

ECSTaskDefinition

+

Representation of an AWS ECS Task Definition

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ARN of the task definition

region

The region of the task definition.

family

The name of a family that this task definition is registered to.

task_role_arn

The short name or full Amazon Resource Name (ARN) of the AWS Identity and Access Management role that grants containers in the task permission to call AWS APIs on your behalf.

execution_role_arn

The Amazon Resource Name (ARN) of the task execution role that grants the Amazon ECS container agent permission to make AWS API calls on your behalf.

network_mode

The Docker networking mode to use for the containers in the task. The valid values are none, bridge, awsvpc, and host. If no network mode is specified, the default is bridge.

revision

The revision of the task in a particular family.

status

The status of the task definition.

compatibilities

The task launch types the task definition validated against during task definition registration.

runtime_platform_cpu_architecture

The CPU architecture.

runtime_platform_operating_system_family

The operating system.

requires_compatibilities

The task launch types the task definition was validated against.

cpu

The number of cpu units used by the task.

memory

The amount (in MiB) of memory used by the task.

pid_mode

The process namespace to use for the containers in the task.

ipc_mode

The IPC resource namespace to use for the containers in the task.

proxy_configuration_type

The proxy type.

proxy_configuration_container_name

The name of the container that will serve as the App Mesh proxy.

registered_at

The Unix timestamp for the time when the task definition was registered.

deregistered_at

The Unix timestamp for the time when the task definition was deregistered.

registered_by

The principal that registered the task definition.

ephemeral_storage_size_in_gib

The total amount, in GiB, of ephemeral storage to set for the task.

+
+

Relationships

+
    +
  • ECSTaskDefinition are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(ECSTaskDefinition)
    +```
    +
    +
    +
  • +
  • An ECSTask has an ECSTaskDefinition.

    +
    ```
    +(ECSTask)-[HAS_TASK_DEFINITION]->(ECSTaskDefinition)
    +```
    +
    +
    +
  • +
+
+
+
+

ECSContainerDefinition

+

Representation of an AWS ECS Container Definition

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ARN of the task definition, plus the container definition name

region

The region of the container definition.

name

The name of a container.

image

The image used to start a container. This string is passed directly to the Docker daemon.

cpu

The number of cpu units reserved for the container.

memory

The amount (in MiB) of memory to present to the container.

memory_reservation

The soft limit (in MiB) of memory to reserve for the container.

links

The links parameter allows containers to communicate with each other without the need for port mappings.

essential

If the essential parameter of a container is marked as true, and that container fails or stops for any reason, all other containers that are part of the task are stopped.

entry_point

The entry point that’s passed to the container.

command

The command that’s passed to the container.

start_timeout

Time duration (in seconds) to wait before giving up on resolving dependencies for a container.

stop_timeout

Time duration (in seconds) to wait before the container is forcefully killed if it doesn’t exit normally on its own.

hostname

The hostname to use for your container.

user

The user to use inside the container.

working_directory

The working directory to run commands inside the container in.

disable_networking

When this parameter is true, networking is disabled within the container.

privileged

When this parameter is true, the container is given elevated privileges on the host container instance (similar to the root user).

readonly_root_filesystem

When this parameter is true, the container is given read-only access to its root file system.

dns_servers

A list of DNS servers that are presented to the container.

dns_search_domains

A list of DNS search domains that are presented to the container.

docker_security_options

A list of strings to provide custom labels for SELinux and AppArmor multi-level security systems. This field isn’t valid for containers in tasks using the Fargate launch type.

interactive

When this parameter is true, you can deploy containerized applications that require stdin or a tty to be allocated.

pseudo_terminal

When this parameter is true, a TTY is allocated.

+
+

Relationships

+
    +
  • ECSTaskDefinitions have ECSContainerDefinitions

    +
    ```
    +(ECSTaskDefinition)-[HAS_CONTAINER_DEFINITION]->(ECSContainerDefinition)
    +```
    +
    +
    +
  • +
+
+
+
+

ECSTask

+

Representation of an AWS ECS Task

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ARN of the task

region

The region of the task.

arn

The arn of the task.

availability_zone

The Availability Zone for the task.

capacity_provider_name

The capacity provider that’s associated with the task.

cluster_arn

The ARN of the cluster that hosts the task.

connectivity

The connectivity status of a task.

connectivity_at

The Unix timestamp for the time when the task last went into CONNECTED status.

container_instance_arn

The ARN of the container instances that host the task.

cpu

The number of CPU units used by the task as expressed in a task definition.

created_at

The Unix timestamp for the time when the task was created. More specifically, it’s for the time when the task entered the PENDING state.

desired_status

The desired status of the task.

enable_execute_command

Determines whether execute command functionality is enabled for this task.

execution_stopped_at

The Unix timestamp for the time when the task execution stopped.

group

The name of the task group that’s associated with the task.

health_status

The health status for the task.

last_status

The last known status for the task.

launch_type

The infrastructure where your task runs on.

memory

The amount of memory (in MiB) that the task uses as expressed in a task definition.

platform_version

The platform version where your task runs on.

platform_family

The operating system that your tasks are running on.

pull_started_at

The Unix timestamp for the time when the container image pull began.

pull_stopped_at

The Unix timestamp for the time when the container image pull completed.

started_at

The Unix timestamp for the time when the task started. More specifically, it’s for the time when the task transitioned from the PENDING state to the RUNNING state.

started_by

The tag specified when a task is started. If an Amazon ECS service started the task, the startedBy parameter contains the deployment ID of that service.

stop_code

The stop code indicating why a task was stopped.

stopped_at

The Unix timestamp for the time when the task was stopped. More specifically, it’s for the time when the task transitioned from the RUNNING state to the STOPPED state.

stopped_reason

The reason that the task was stopped.

stopping_at

The Unix timestamp for the time when the task stops. More specifically, it’s for the time when the task transitions from the RUNNING state to STOPPED.

task_definition_arn

The ARN of the task definition that creates the task.

version

The version counter for the task.

ephemeral_storage_size_in_gib

The total amount, in GiB, of ephemeral storage to set for the task.

+
+

Relationships

+
    +
  • ECSClusters have ECSTasks

    +
    ```
    +(ECSCluster)-[HAS_TASK]->(ECSTask)
    +```
    +
    +
    +
  • +
  • ECSContainerInstances have ECSTasks

    +
    ```
    +(ECSContainerInstance)-[HAS_TASK]->(ECSTask)
    +```
    +
    +
    +
  • +
  • ECSTasks have ECSTaskDefinitions

    +
    ```
    +(ECSTask)-[HAS_TASK_DEFINITION]->(ECSTaskDefinition)
    +```
    +
    +
    +
  • +
+
+
+
+

ECSContainer

+

Representation of an AWS ECS Container

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ARN of the container

region

The region of the container.

arn

The arn of the container.

task_arn

The ARN of the task.

name

The name of the container.

image

The image used for the container.

image_digest

The container image manifest digest.

runtime_id

The ID of the Docker container.

last_status

The last known status of the container.

exit_code

The exit code returned from the container.

reason

A short (255 max characters) human-readable string to provide additional details about a running or stopped container.

health_status

The health status of the container.

cpu

The number of CPU units set for the container.

memory

The hard limit (in MiB) of memory set for the container.

memory_reservation

The soft limit (in MiB) of memory set for the container.

gpu_ids

The IDs of each GPU assigned to the container.

+
+

Relationships

+
    +
  • ECSTasks have ECSContainers

    +
    ```
    +(ECSTask)-[HAS_CONTAINER]->(ECSContainer)
    +```
    +
    +
    +
  • +
+
+
+
+

SSMInstanceInformation

+

Representation of an AWS SSM InstanceInformation

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ARN of the instance information

region

The region of the instance information.

instance_id

The managed node ID.

ping_status

Connection status of SSM Agent.

last_ping_date_time

The date and time when the agent last pinged the Systems Manager service.

agent_version

The version of SSM Agent running on your Linux managed node.

is_latest_version

Indicates whether the latest version of SSM Agent is running on your Linux managed node. This field doesn’t indicate whether or not the latest version is installed on Windows managed nodes, because some older versions of Windows Server use the EC2Config service to process Systems Manager requests.

platform_type

The operating system platform type.

platform_name

The name of the operating system platform running on your managed node.

platform_version

The version of the OS platform running on your managed node.

activation_id

The activation ID created by AWS Systems Manager when the server or virtual machine (VM) was registered.

iam_role

The AWS Identity and Access Management (IAM) role assigned to the on-premises Systems Manager managed node. This call doesn’t return the IAM role for Amazon Elastic Compute Cloud (Amazon EC2) instances.

registration_date

The date the server or VM was registered with AWS as a managed node.

resource_type

The type of instance. Instances are either EC2 instances or managed instances.

name

The name assigned to an on-premises server, edge device, or virtual machine (VM) when it is activated as a Systems Manager managed node. The name is specified as the DefaultInstanceName property using the CreateActivation command.

ip_address

The IP address of the managed node.

computer_name

The fully qualified host name of the managed node.

association_status

The status of the association.

last_association_execution_date

The date the association was last run.

last_successful_association_execution_date

The last date the association was successfully run.

source_id

The ID of the source resource. For AWS IoT Greengrass devices, SourceId is the Thing name.

source_type

The type of the source resource. For AWS IoT Greengrass devices, SourceType is AWS::IoT::Thing.

+
+

Relationships

+
    +
  • SSMInstanceInformation is a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(SSMInstanceInformation)
    +```
    +
    +
    +
  • +
  • SSMInstanceInformation is a resource of an EC2Instance

    +
    ```
    +(EC2Instance)-[HAS_INFORMATION]->(SSMInstanceInformation)
    +```
    +
    +
    +
  • +
+
+
+
+

SSMInstancePatch

+

Representation of an AWS SSM PatchComplianceData

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ARN of the instance patch

region

The region of the instance patch.

instance_id

The managed node ID.

title

The title of the patch.

kb_id

The operating system-specific ID of the patch.

classification

The classification of the patch, such as SecurityUpdates, Updates, and CriticalUpdates.

severity

The severity of the patch such as Critical, Important, and Moderate.

state

The state of the patch on the managed node, such as INSTALLED or FAILED.

installed_time

The date/time the patch was installed on the managed node. Not all operating systems provide this level of information.

cve_ids

The IDs of one or more Common Vulnerabilities and Exposure (CVE) issues that are resolved by the patch.

+
+

Relationships

+
    +
  • SSMInstancePatch is a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(SSMInstancePatch)
    +```
    +
    +
    +
  • +
  • EC2Instances have SSMInstancePatches

    +
    ```
    +(EC2Instance)-[HAS_INFORMATION]->(SSMInstancePatch)
    +```
    +
    +
    +
  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/azure/config.html b/modules/azure/config.html new file mode 100644 index 0000000000..c9ee5cf0c7 --- /dev/null +++ b/modules/azure/config.html @@ -0,0 +1,581 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Azure Configuration — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Azure Configuration

+

Follow these steps to analyze Microsoft Azure assets with Cartography:

+
    +
  1. Set up an Azure identity for Cartography to use, and ensure that this identity has the built-in Azure Reader role attached:

    +
      +
    • Authenticate: $ az login

    • +
    • Create a Service Principal: $ az ad sp create-for-rbac --name cartography --role Reader

    • +
    • Note the values of the tenant, appId, and password fields

    • +
    +
  2. +
  3. Populate environment variables with the values generated in the previous step (e.g., AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET)

  4. +
  5. Call the cartography CLI with: +.. code-block:: bash

    +
    +

    –azure-sp-auth –azure-sync-all-subscriptions –azure-tenant-id ${AZURE_TENANT_ID} –azure-client-id ${AZURE_CLIENT_ID} –azure-client-secret-env-var AZURE_CLIENT_SECRET

    +
    +
  6. +
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/azure/index.html b/modules/azure/index.html new file mode 100644 index 0000000000..fb41ce8c30 --- /dev/null +++ b/modules/azure/index.html @@ -0,0 +1,572 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Microsoft Azure — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Microsoft Azure

+

The azure module has the following coverage:

+
    +
  • CosmosDB

  • +
  • SQL

  • +
  • Storage

  • +
  • Virtual Machine

  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/azure/schema.html b/modules/azure/schema.html new file mode 100644 index 0000000000..83555310d3 --- /dev/null +++ b/modules/azure/schema.html @@ -0,0 +1,3656 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Azure Schema — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Azure Schema

+
+

AzureTenant

+

Representation of an Azure Tenant.

+ ++++ + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The Azure Tenant ID number

+
+

Relationships

+
    +
  • Azure Principal is part of the Azure Account.

    +
    ```
    +(AzureTenant)-[RESOURCE]->(AzurePrincipal)
    +```
    +
    +
    +
  • +
+
+
+
+

AzurePrincipal

+

Representation of an Azure Principal..

+ ++++ + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

email

Email of the Azure Principal

+
+

Relationships

+
    +
  • Azure Principal is part of the Azure Account.

    +
    ```
    +(AzurePrincipal)-[RESOURCE]->(AzureTenant)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureSubscription

+

Representation of an Azure Subscription..

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The Azure Subscription ID number

name

The friendly name that identifies the subscription

path

The full ID for the Subscription

state

Can be one of Enabled | Disabled | Deleted | PastDue | Warned

+
+

Relationships

+
    +
  • Azure Tenant contains one or more Subscriptions.

    +
    ```
    +(AzureTenant)-[RESOURCE]->(AzureSubscription)
    +```
    +
    +
    +
  • +
+
+
+
+

VirtualMachine

+

Representation of an Azure Virtual Machine.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The Azure Virtual Machine ID number

type

The type of the resource

location

The location where Virtual Machine is created

resourcegroup

The Resource Group where Virtual Machine is created

name

The friendly name that identifies the Virtual Machine

plan

The plan associated with the Virtual Machine

size

The size of the Virtual Machine

license_type

The type of license

computer_name

The computer name

identity_type

The type of identity used for the virtual machine

zones

The Virtual Machine zones

ultra_ssd_enabled

Enables or disables a capability on the virtual machine or virtual machine scale set.

priority

Specifies the priority for the virtual machine

eviction_policy

Specifies the eviction policy for the Virtual Machine

+
+

Relationships

+
    +
  • Azure Subscription contains one or more Virtual Machines.

    +
    ```
    +(AzureSubscription)-[RESOURCE]->(VirtualMachine)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureDataDisk

+

Representation of an Azure Data Disk.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The Azure Data Disk ID number

lun

Specifies the logical unit number of the data disk

name

The data disk name

vhd

The virtual hard disk associated with data disk

image

The source user image virtual hard disk

size

The size of the disk in GB

caching

Specifies the caching requirement

createoption

Specifies how the disk should be created

write_accelerator_enabled

Specifies whether writeAccelerator should be enabled or disabled on the data disk

managed_disk_storage_type

The data disk storage type

+
+

Relationships

+
    +
  • Azure Virtual Machines are attached to Data Disks.

    +
    ```
    +(VirtualMachine)-[ATTACHED_TO]->(AzureDataDisk)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureDisk

+

Representation of an Azure Disk.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The Azure Disk ID number

type

The type of the resource

location

The location where Disk is created

resourcegroup

The Resource Group where Disk is created

name

The friendly name that identifies the Disk

createoption

Specifies how the disk should be created

disksizegb

The size of the disk in GB

encryption

Specifies whether the disk has encryption enabled

maxshares

Specifies how many machines can share the disk

ostype

The operating system type of the disk

tier

Performance Tier associated with the disk

sku

The disk sku name

zones

The logical zone list for disk

+
+

Relationships

+
    +
  • Azure Subscription contains one or more Disks.

    +
    ```
    +(AzureSubscription)-[RESOURCE]->(AzureDisk)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureSnapshot

+

Representation of an Azure Snapshot.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The Azure Snapshot ID number

type

The type of the resource

location

The location where snapshot is created

resourcegroup

The Resource Group where snapshot is created

name

The friendly name that identifies the snapshot

createoption

Specifies how the disk should be created

disksizegb

The size of the snapshot in GB

encryption

Specifies whether the snapshot has encryption enabled

incremental

Indicates whether a snapshot is incremental or not

network_access_policy

Policy for accessing the snapshot via network

ostype

The operating system type of the snapshot

tier

Performance Tier associated with the snapshot

sku

The snapshot sku name

zones

The logical zone list for snapshot

+
+

Relationships

+
    +
  • Azure Subscription contains one or more Snapshots.

    +
    ```
    +(AzureSubscription)-[RESOURCE]->(AzureSnapshot)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureSQLServer

+

Representation of an AzureSQLServer.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The resource ID

location

The location where the resource is created

resourcegroup

The Resource Group where SQL Server is created

name

The friendly name that identifies the SQL server

kind

Specifies the kind of SQL server

state

The state of the server

version

The version of the server

+
+

Relationships

+
    +
  • Azure Subscription contains one or more SQL Servers.

    +
    ```
    +(AzureSubscription)-[RESOURCE]->(AzureSQLServer)
    +```
    +
    +
    +
  • +
  • Azure SQL Server can be used by one or more Azure Server DNS Aliases.

    +
    ```
    +(AzureSQLServer)-[USED_BY]->(AzureServerDNSAlias)
    +```
    +
    +
    +
  • +
  • Azure SQL Server can be administered by one or more Azure Server AD Administrators.

    +
    ```
    +(AzureSQLServer)-[ADMINISTERED_BY]->(AzureServerADAdministrator)
    +```
    +
    +
    +
  • +
  • Azure SQL Server has one or more Azure Recoverable Database.

    +
    ```
    +(AzureSQLServer)-[RESOURCE]->(AzureRecoverableDatabase)
    +```
    +
    +
    +
  • +
  • Azure SQL Server has one or more Azure Restorable Dropped Database.

    +
    ```
    +(AzureSQLServer)-[RESOURCE]->(AzureRestorableDroppedDatabase)
    +```
    +
    +
    +
  • +
  • Azure SQL Server has one or more Azure Failover Group.

    +
    ```
    +(AzureSQLServer)-[RESOURCE]->(AzureFailoverGroup)
    +```
    +
    +
    +
  • +
  • Azure SQL Server has one or more Azure Elastic Pool.

    +
    ```
    +(AzureSQLServer)-[RESOURCE]->(AzureElasticPool)
    +```
    +
    +
    +
  • +
  • Azure SQL Server has one or more Azure SQL Database.

    +
    ```
    +(AzureSQLServer)-[RESOURCE]->(AzureSQLDatabase)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureServerDNSAlias

+

Representation of an AzureServerDNSAlias.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The resource ID

name

The name of the server DNS alias

dnsrecord

The fully qualified DNS record for alias.

+
+

Relationships

+
    +
  • Azure SQL Server can be used by one or more Azure Server DNS Aliases.

    +
    ```
    +(AzureSQLServer)-[USED_BY]->(AzureServerDNSAlias)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureServerADAdministrator

+

Representation of an AzureServerADAdministrator.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The resource ID

name

The name of the resource.

administratortype

The type of the server administrator.

login

The login name of the server administrator.

+
+

Relationships

+
    +
  • Azure SQL Server can be administered by one or more Azure Server AD Administrators.

    +
    ```
    +(AzureSQLServer)-[ADMINISTERED_BY]->(AzureServerADAdministrator)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureRecoverableDatabase

+

Representation of an AzureRecoverableDatabase.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The resource ID

name

The name of the resource.

edition

The edition of the database.

servicelevelobjective

The service level objective name of the database.

lastbackupdate

The last available backup date of the database (ISO8601 format).

+
+

Relationships

+
    +
  • Azure SQL Server has one or more Azure Recoverable Database.

    +
    ```
    +(AzureSQLServer)-[RESOURCE]->(AzureRecoverableDatabase)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureRestorableDroppedDatabase

+

Representation of an AzureRestorableDroppedDatabase.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The resource ID

name

The name of the resource.

location

The geo-location where the resource lives.

databasename

The name of the database.

creationdate

The creation date of the database (ISO8601 format).

deletiondate

The deletion date of the database (ISO8601 format).

restoredate

The earliest restore date of the database (ISO8601 format).

edition

The edition of the database.

servicelevelobjective

The service level objective name of the database.

maxsizebytes

The max size in bytes of the database.

+
+

Relationships

+
    +
  • Azure SQL Server has one or more Azure Restorable Dropped Database.

    +
    ```
    +(AzureSQLServer)-[RESOURCE]->(AzureRestorableDroppedDatabase)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureFailoverGroup

+

Representation of an AzureFailoverGroup.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The resource ID

name

The name of the resource.

location

The geo-location where the resource lives.

replicationrole

Local replication role of the failover group instance.

replicationstate

Replication state of the failover group instance.

+
+

Relationships

+
    +
  • Azure SQL Server has one or more Azure Failover Group.

    +
    ```
    +(AzureSQLServer)-[RESOURCE]->(AzureFailoverGroup)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureElasticPool

+

Representation of an AzureElasticPool.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The resource ID

name

The name of the resource.

location

The location of the resource.

kind

The kind of elastic pool.

creationdate

The creation date of the elastic pool (ISO8601 format).

state

The state of the elastic pool.

maxsizebytes

The storage limit for the database elastic pool in bytes.

licensetype

The license type to apply for this elastic pool.

zoneredundant

Specifies whether or not this elastic pool is zone redundant, which means the replicas of this elastic pool will be spread across multiple availability zones.

+
+

Relationships

+
    +
  • Azure SQL Server has one or more Azure Elastic Pool.

    +
    ```
    +(AzureSQLServer)-[RESOURCE]->(AzureElasticPool)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureSQLDatabase

+

Representation of an AzureSQLDatabase.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The resource ID

name

The name of the resource.

location

The location of the resource.

kind

The kind of database.

creationdate

The creation date of the database (ISO8601 format).

databaseid

The ID of the database.

maxsizebytes

The max size of the database expressed in bytes.

licensetype

The license type to apply for this database.

secondarylocation

The default secondary region for this database.

elasticpoolid

The resource identifier of the elastic pool containing this database.

collation

The collation of the database.

failovergroupid

Failover Group resource identifier that this database belongs to.

zoneredundant

Whether or not this database is zone redundant, which means the replicas of this database will be spread across multiple availability zones.

restorabledroppeddbid

The resource identifier of the restorable dropped database associated with create operation of this database.

recoverabledbid

The resource identifier of the recoverable database associated with create operation of this database.

+
+

Relationships

+
    +
  • Azure SQL Server has one or more Azure SQL Database.

    +
    ```
    +(AzureSQLServer)-[RESOURCE]->(AzureSQLDatabase)
    +```
    +
    +
    +
  • +
  • Azure SQL Database contains one or more Azure Replication Links.

    +
    ```
    +(AzureSQLDatabase)-[CONTAINS]->(AzureReplicationLink)
    +```
    +
    +
    +
  • +
  • Azure SQL Database contains a Database Threat Detection Policy.

    +
    ```
    +(AzureSQLDatabase)-[CONTAINS]->(AzureDatabaseThreatDetectionPolicy)
    +```
    +
    +
    +
  • +
  • Azure SQL Database contains one or more Restore Points.

    +
    ```
    +(AzureSQLDatabase)-[CONTAINS]->(AzureRestorePoint)
    +```
    +
    +
    +
  • +
  • Azure SQL Database contains Transparent Data Encryption.

    +
    ```
    +(AzureSQLDatabase)-[CONTAINS]->(AzureTransparentDataEncryption)
    +```
    +
    +
    +
  • +
+
+
+ +
+

AzureDatabaseThreatDetectionPolicy

+

Representation of an AzureDatabaseThreatDetectionPolicy.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The resource ID

name

The name of the resource.

location

The geo-location where the resource lives.

kind

The kind of the resource.

emailadmins

Specifies that the alert is sent to the account administrators.

emailaddresses

Specifies the semicolon-separated list of e-mail addresses to which the alert is sent.

retentiondays

Specifies the number of days to keep in the Threat Detection audit logs.

state

Specifies the state of the policy.

storageendpoint

Specifies the blob storage endpoint.

useserverdefault

Specifies whether to use the default server policy.

disabledalerts

Specifies the semicolon-separated list of alerts that are disabled, or empty string to disable no alerts.

+
+

Relationships

+
    +
  • Azure SQL Database contains a Database Threat Detection Policy.

    +
    ```
    +(AzureSQLDatabase)-[CONTAINS]->(AzureDatabaseThreatDetectionPolicy)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureRestorePoint

+

Representation of an AzureRestorePoint.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The resource ID

name

The name of the resource.

location

The geo-location where the resource lives.

restoredate

The earliest time to which this database can be restored.

restorepointtype

The type of restore point.

creationdate

The time the backup was taken.

+
+

Relationships

+
    +
  • Azure SQL Database contains one or more Restore Points.

    +
    ```
    +(AzureSQLDatabase)-[CONTAINS]->(AzureRestorePoint)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureTransparentDataEncryption

+

Representation of an AzureTransparentDataEncryption.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The resource ID

name

The name of the resource.

location

The resource location.

status

The status of the database transparent data encryption.

+
+

Relationships

+
    +
  • Azure SQL Database contains Transparent Data Encryption.

    +
    ```
    +(AzureSQLDatabase)-[CONTAINS]->(AzureTransparentDataEncryption)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureStorageAccount

+

Representation of an AzureStorageAccount.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Fully qualified resource ID for the resource.

type

The type of the resource.

location

The geo-location where the resource lives.

resourcegroup

The Resource Group where the storage account is created

name

The name of the resource.

kind

Gets the Kind of the resource.

creationtime

Gets the creation date and time of the storage account in UTC.

hnsenabled

Specifies if the Account HierarchicalNamespace is enabled.

primarylocation

Gets the location of the primary data center for the storage account.

secondarylocation

Gets the location of the geo-replicated secondary for the storage account.

provisioningstate

Gets the status of the storage account at the time the operation was called.

statusofprimary

Gets the status availability status of the primary location of the storage account.

statusofsecondary

Gets the status availability status of the secondary location of the storage account.

supportshttpstrafficonly

Allows https traffic only to storage service if sets to true.

+
+

Relationships

+
    +
  • Azure Subscription contains one or more Storage Accounts.

    +
    ```
    +(AzureSubscription)-[RESOURCE]->(AzureStorageAccount)
    +```
    +
    +
    +
  • +
  • Azure Storage Accounts uses one or more Queue Services.

    +
    ```
    +(AzureStorageAccount)-[USES]->(AzureStorageQueueService)
    +```
    +
    +
    +
  • +
  • Azure Storage Accounts uses one or more Table Services.

    +
    ```
    +(AzureStorageAccount)-[USES]->(AzureStorageTableService)
    +```
    +
    +
    +
  • +
  • Azure Storage Accounts uses one or more File Services.

    +
    ```
    +(AzureStorageAccount)-[USES]->(AzureStorageFileService)
    +```
    +
    +
    +
  • +
  • Azure Storage Accounts uses one or more Blob Services.

    +
    ```
    +(AzureStorageAccount)-[USES]->(AzureStorageBlobService)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureStorageQueueService

+

Representation of an AzureStorageQueueService.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Fully qualified resource ID for the resource.

type

The type of the resource.

name

The name of the queue service.

+
+

Relationships

+
    +
  • Azure Storage Accounts uses one or more Queue Services.

    +
    ```
    +(AzureStorageAccount)-[USES]->(AzureStorageQueueService)
    +```
    +
    +
    +
  • +
  • Queue Service contains one or more queues.

    +
    ```
    +(AzureStorageQueueService)-[CONTAINS]->(AzureStorageQueue)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureStorageTableService

+

Representation of an AzureStorageTableService.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Fully qualified resource ID for the resource.

type

The type of the resource.

name

The name of the table service.

+
+

Relationships

+
    +
  • Azure Storage Accounts uses one or more Table Services.

    +
    ```
    +(AzureStorageAccount)-[USES]->(AzureStorageTableService)
    +```
    +
    +
    +
  • +
  • Table Service contains one or more tables.

    +
    ```
    +(AzureStorageTableService)-[CONTAINS]->(AzureStorageTable)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureStorageFileService

+

Representation of an AzureStorageFileService.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Fully qualified resource ID for the resource.

type

The type of the resource.

name

The name of the file service.

+
+

Relationships

+
    +
  • Azure Storage Accounts uses one or more File Services.

    +
    ```
    +(AzureStorageAccount)-[USES]->(AzureStorageFileService)
    +```
    +
    +
    +
  • +
  • Table Service contains one or more file shares.

    +
    ```
    +(AzureStorageFileService)-[CONTAINS]->(AzureStorageFileShare)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureStorageBlobService

+

Representation of an AzureStorageBlobService.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Fully qualified resource ID for the resource.

type

The type of the resource.

name

The name of the blob service.

+
+

Relationships

+
    +
  • Azure Storage Accounts uses one or more Blob Services.

    +
    ```
    +(AzureStorageAccount)-[USES]->(AzureStorageBlobService)
    +```
    +
    +
    +
  • +
  • Blob Service contains one or more blob containers.

    +
    ```
    +(AzureStorageBlobService)-[CONTAINS]->(AzureStorageBlobContainer)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureStorageQueue

+

Representation of an AzureStorageQueue.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Fully qualified resource ID for the resource.

type

The type of the resource.

name

The name of the queue.

+
+

Relationships

+
    +
  • Queue Service contains one or more queues.

    +
    ```
    +(AzureStorageQueueService)-[CONTAINS]->(AzureStorageQueue)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureStorageTable

+

Representation of an AzureStorageTable.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Fully qualified resource ID for the resource.

type

The type of the resource.

name

The name of the table resource.

tablename

Table name under the specified account.

+
+

Relationships

+
    +
  • Table Service contains one or more tables.

    +
    ```
    +(AzureStorageTableService)-[CONTAINS]->(AzureStorageTable)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureStorageFileShare

+

Representation of an AzureStorageFileShare.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Fully qualified resource ID for the resource.

type

The type of the resource.

name

The name of the resource.

lastmodifiedtime

Specifies the date and time the share was last modified.

sharequota

The maximum size of the share, in gigabytes.

accesstier

Specifies the access tier for the share.

deleted

Indicates whether the share was deleted.

accesstierchangetime

Indicates the last modification time for share access tier.

accesstierstatus

Indicates if there is a pending transition for access tier.

deletedtime

The deleted time if the share was deleted.

enabledprotocols

The authentication protocol that is used for the file share.

remainingretentiondays

Remaining retention days for share that was soft deleted.

shareusagebytes

The approximate size of the data stored on the share.

version

The version of the share.

+
+

Relationships

+
    +
  • File Service contains one or more file shares.

    +
    ```
    +(AzureStorageTableService)-[CONTAINS]->(AzureStorageFileShare)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureStorageBlobContainer

+

Representation of an AzureStorageBlobContainer.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Fully qualified resource ID for the resource.

type

The type of the resource.

name

The name of the resource.

deleted

Indicates whether the blob container was deleted.

deletedtime

Blob container deletion time.

defaultencryptionscope

Default the container to use specified encryption scope for all writes.

publicaccess

Specifies whether data in the container may be accessed publicly and the level of access.

leasestatus

The lease status of the container.

leasestate

Lease state of the container.

lastmodifiedtime

Specifies the date and time the container was last modified.

remainingretentiondays

Specifies the remaining retention days for soft deleted blob container.

version

The version of the deleted blob container.

hasimmutabilitypolicy

Specifies the if the container has an ImmutabilityPolicy or not.

haslegalhold

Specifies if the container has any legal hold tags.

leaseduration

Specifies whether the lease on a container is of infinite or fixed duration, only when the container is leased.

+
+

Relationships

+
    +
  • Blob Service contains one or more blob containers.

    +
    ```
    +(AzureStorageBlobService)-[CONTAINS]->(AzureStorageBlobContainer)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureCosmosDBAccount

+

Representation of an AzureCosmosDBAccount.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The unique resource identifier of the ARM resource.

location

The location of the resource group to which the resource belongs.

resourcegroup

The Resource Group where the database account is created.

name

The name of the ARM resource.

kind

Indicates the type of database account.

type

The type of Azure resource.

ipranges

List of IpRules.

capabilities

List of Cosmos DB capabilities for the account.

documentendpoint

The connection endpoint for the Cosmos DB database account.

virtualnetworkfilterenabled

Flag to indicate whether to enable/disable Virtual Network ACL rules.

enableautomaticfailover

Enables automatic failover of the write region in the rare event that the region is unavailable due to an outage.

provisioningstate

The status of the Cosmos DB account at the time the operation was called.

multiplewritelocations

Enables the account to write in multiple locations.

accountoffertype

The offer type for the Cosmos DB database account.

publicnetworkaccess

Whether requests from Public Network are allowed.

enablecassandraconnector

Enables the cassandra connector on the Cosmos DB C* account.

connectoroffer

The cassandra connector offer type for the Cosmos DB database C* account.

disablekeybasedmetadatawriteaccess

Disable write operations on metadata resources (databases, containers, throughput) via account keys.

keyvaulturi

The URI of the key vault.

enablefreetier

Flag to indicate whether Free Tier is enabled.

enableanalyticalstorage

Flag to indicate whether to enable storage analytics.

defaultconsistencylevel

The default consistency level and configuration settings of the Cosmos DB account.

maxstalenessprefix

When used with the Bounded Staleness consistency level, this value represents the number of stale requests tolerated.

maxintervalinseconds

When used with the Bounded Staleness consistency level, this value represents the time amount of staleness (in seconds) tolerated.

+
+

Relationships

+
    +
  • Azure Subscription contains one or more database accounts.

    +
    ```
    +(AzureSubscription)-[RESOURCE]->(AzureCosmosDBAccount)
    +```
    +
    +
    +
  • +
  • Azure Database Account can be read from, written from and is associated with Azure CosmosDB Locations.

    +
    ```
    +(AzureCosmosDBAccount)-[CAN_WRITE_FROM]->(AzureCosmosDBLocation)
    +```
    +(AzureCosmosDBAccount)-[CAN_READ_FROM]->(AzureCosmosDBLocation)
    +```
    +(AzureCosmosDBAccount)-[ASSOCIATED_WITH]->(AzureCosmosDBLocation)
    +```
    +
    +
    +
  • +
  • Azure Database Account contains one or more Cors Policy.

    +
    ```
    +(AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBCorsPolicy)
    +```
    +
    +
    +
  • +
  • Azure Database Account contains one or more failover policies.

    +
    ```
    +(AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBAccountFailoverPolicy)
    +```
    +
    +
    +
  • +
  • Azure Database Account is configured with one or more private endpoint connections.

    +
    ```
    +(AzureCosmosDBAccount)-[CONFIGURED_WITH]->(AzureCDBPrivateEndpointConnection)
    +```
    +
    +
    +
  • +
  • Azure Database Account is configured with one or more virtual network rules.

    +
    ```
    +(AzureCosmosDBAccount)-[CONFIGURED_WITH]->(AzureCosmosDBVirtualNetworkRule)
    +```
    +
    +
    +
  • +
  • Azure Database Account contains one or more SQL databases.

    +
    ```
    +(AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBSqlDatabase)
    +```
    +
    +
    +
  • +
  • Azure Database Account contains one or more Cassandra keyspace.

    +
    ```
    +(AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBCassandraKeyspace)
    +```
    +
    +
    +
  • +
  • Azure Database Account contains one or more MongoDB Database.

    +
    ```
    +(AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBMongoDBDatabase)
    +```
    +
    +
    +
  • +
  • Azure Database Account contains one or more table resource.

    +
    ```
    +(AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBTableResource)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureCosmosDBLocation

+

Representation of an Azure CosmosDB Location.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The unique identifier of the region within the database account.

locationname

The name of the region.

documentendpoint

The connection endpoint for the specific region.

provisioningstate

The status of the Cosmos DB account at the time the operation was called.

failoverpriority

The failover priority of the region.

iszoneredundant

Flag to indicate whether or not this region is an AvailabilityZone region.

+
+

Relationships

+
    +
  • Azure Database Account has write permissions from, read permissions from and is associated with Azure CosmosDB Locations.

    +
    ```
    +(AzureCosmosDBAccount)-[CAN_WRITE_FROM]->(AzureCosmosDBLocation)
    +```
    +(AzureCosmosDBAccount)-[CAN_READ_FROM]->(AzureCosmosDBLocation)
    +```
    +(AzureCosmosDBAccount)-[ASSOCIATED_WITH]->(AzureCosmosDBLocation)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureCosmosDBCorsPolicy

+

Representation of an Azure Cosmos DB Cors Policy.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The unique resource identifier for Cors Policy.

allowedorigins

The origin domains that are permitted to make a request against the service via CORS.

allowedmethods

The methods (HTTP request verbs) that the origin domain may use for a CORS request.

allowedheaders

The request headers that the origin domain may specify on the CORS request.

exposedheaders

The response headers that may be sent in the response to the CORS request and exposed by the browser to the request issuer.

maxageinseconds

The maximum amount time that a browser should cache the preflight OPTIONS request.

+
+

Relationships

+
    +
  • Azure Database Account contains one or more Cors Policy.

    +
    ```
    +(AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBCorsPolicy)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureCosmosDBAccountFailoverPolicy

+

Representation of an Azure Database Account Failover Policy.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The unique identifier of the region in which the database account replicates to.

locationname

The name of the region in which the database account exists.

failoverpriority

The failover priority of the region. A failover priority of 0 indicates a write region.

+
+

Relationships

+
    +
  • Azure Database Account contains one or more failover policies.

    +
    ```
    +(AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBAccountFailoverPolicy)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureCDBPrivateEndpointConnection

+

Representation of an Azure Cosmos DB Private Endpoint Connection.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Fully qualified resource Id for the resource.

name

The name of the resource.

privateendpointid

Resource id of the private endpoint.

status

The private link service connection status.

actionrequired

Any action that is required beyond basic workflow (approve/ reject/ disconnect).

+
+

Relationships

+
    +
  • Azure Database Account is configured with one or more private endpoint connections.

    +
    ```
    +(AzureCosmosDBAccount)-[CONFIGURED_WITH]->(AzureCDBPrivateEndpointConnection)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureCosmosDBVirtualNetworkRule

+

Representation of an Azure Cosmos DB Virtual Network Rule.

+ ++++ + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Resource ID of a subnet.

ignoremissingvnetserviceendpoint

Create firewall rule before the virtual network has vnet service endpoint enabled.

+
+

Relationships

+
    +
  • Azure Database Account is configured with one or more virtual network rules.

    +
    ```
    +(AzureCosmosDBAccount)-[CONFIGURED_WITH]->(AzureCosmosDBVirtualNetworkRule)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureCosmosDBSqlDatabase

+

Representation of an AzureCosmosDBSqlDatabase.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The unique resource identifier of the ARM resource.

name

The name of the ARM resource.

type

The type of Azure resource.

location

The location of the resource group to which the resource belongs.

throughput

Value of the Cosmos DB resource throughput or autoscaleSettings.

maxthroughput

Represents maximum throughput, the resource can scale up to.

+
+

Relationships

+
    +
  • Azure Database Account contains one or more SQL databases.

    +
    ```
    +(AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBSqlDatabase)
    +```
    +
    +
    +
  • +
  • SQL Databases contain one or more SQL containers.

    +
    ```
    +(AzureCosmosDBSqlDatabase)-[CONTAINS]->(AzureCosmosDBSqlContainer)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureCosmosDBCassandraKeyspace

+

Representation of an AzureCosmosDBCassandraKeyspace.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The unique resource identifier of the ARM resource.

name

The name of the ARM resource.

type

The type of Azure resource.

location

The location of the resource group to which the resource belongs.

throughput

Value of the Cosmos DB resource throughput or autoscaleSettings.

maxthroughput

Represents maximum throughput, the resource can scale up to.

+
+

Relationships

+
    +
  • Azure Database Account contains one or more Cassandra keyspace.

    +
    ```
    +(AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBCassandraKeyspace)
    +```
    +
    +
    +
  • +
  • Cassandra Keyspace contains one or more Cassandra tables.

    +
    ```
    +(AzureCosmosDBCassandraKeyspace)-[CONTAINS]->(AzureCosmosDBCassandraTable)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureCosmosDBMongoDBDatabase

+

Representation of an AzureCosmosDBMongoDBDatabase.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The unique resource identifier of the ARM resource.

name

The name of the ARM resource.

type

The type of Azure resource.

location

The location of the resource group to which the resource belongs.

throughput

Value of the Cosmos DB resource throughput or autoscaleSettings.

maxthroughput

Represents maximum throughput, the resource can scale up to.

+
+

Relationships

+
    +
  • Azure Database Account contains one or more MongoDB Database.

    +
    ```
    +(AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBMongoDBDatabase)
    +```
    +
    +
    +
  • +
  • MongoDB database contains one or more MongoDB collections.

    +
    ```
    +(AzureCosmosDBMongoDBDatabase)-[CONTAINS]->(AzureCosmosDBMongoDBCollection)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureCosmosDBTableResource

+

Representation of an AzureCosmosDBTableResource.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The unique resource identifier of the ARM resource.

name

The name of the ARM resource.

type

The type of Azure resource.

location

The location of the resource group to which the resource belongs.

throughput

Value of the Cosmos DB resource throughput or autoscaleSettings.

maxthroughput

Represents maximum throughput, the resource can scale up to.

+
+

Relationships

+
    +
  • Azure Database Account contains one or more table resource.

    +
    ```
    +(AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBTableResource)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureCosmosDBSqlContainer

+

Representation of an AzureCosmosDBSqlContainer.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The unique resource identifier of the ARM resource.

name

The name of the ARM resource.

type

The type of Azure resource.

location

The location of the resource group to which the resource belongs.

throughput

Value of the Cosmos DB resource throughput or autoscaleSettings.

maxthroughput

Represents maximum throughput, the resource can scale up to.

container

Name of the Cosmos DB SQL container.

defaultttl

Default time to live.

analyticalttl

Specifies the Analytical TTL.

isautomaticindexingpolicy

Indicates if the indexing policy is automatic.

indexingmode

Indicates the indexing mode.

conflictresolutionpolicymode

Indicates the conflict resolution mode.

+
+

Relationships

+
    +
  • SQL Databases contain one or more SQL containers.

    +
    ```
    +(AzureCosmosDBSqlDatabase)-[CONTAINS]->(AzureCosmosDBSqlContainer)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureCosmosDBCassandraTable

+

Representation of an AzureCosmosDBCassandraTable.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The unique resource identifier of the ARM resource.

name

The name of the ARM resource.

type

The type of Azure resource.

location

The location of the resource group to which the resource belongs.

throughput

Value of the Cosmos DB resource throughput or autoscaleSettings.

maxthroughput

Represents maximum throughput, the resource can scale up to.

container

Name of the Cosmos DB Cassandra table.

defaultttl

Time to live of the Cosmos DB Cassandra table.

analyticalttl

Specifies the Analytical TTL.

+
+

Relationships

+
    +
  • Cassandra Keyspace contains one or more Cassandra tables.

    +
    ```
    +(AzureCosmosDBCassandraKeyspace)-[CONTAINS]->(AzureCosmosDBCassandraTable)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureCosmosDBMongoDBCollection

+

Representation of an AzureCosmosDBMongoDBCollection.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The unique resource identifier of the ARM resource.

name

The name of the ARM resource.

type

The type of Azure resource.

location

The location of the resource group to which the resource belongs.

throughput

Value of the Cosmos DB resource throughput or autoscaleSettings.

maxthroughput

Represents maximum throughput, the resource can scale up to.

collectionname

Name of the Cosmos DB MongoDB collection.

analyticalttl

Specifies the Analytical TTL.

+
+

Relationships

+
    +
  • MongoDB database contains one or more MongoDB collections.

    +
    ```
    +(AzureCosmosDBMongoDBDatabase)-[CONTAINS]->(AzureCosmosDBMongoDBCollection)
    +```
    +
    +
    +
  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/bigfix/config.html b/modules/bigfix/config.html new file mode 100644 index 0000000000..a5d67c02d0 --- /dev/null +++ b/modules/bigfix/config.html @@ -0,0 +1,571 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BigFix Configuration — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

BigFix Configuration

+

Follow these steps to analyze BigFix objects with Cartography.

+
    +
  1. Prepare a read-only BigFix username and password.

  2. +
  3. Pass the BigFix username to the --bigfix-username CLI arg.

  4. +
  5. Populate an environment variable with the password.

  6. +
  7. Pass that env var name to the --bigfix_password_env_var CLI arg.

  8. +
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/bigfix/index.html b/modules/bigfix/index.html new file mode 100644 index 0000000000..d35ff2e293 --- /dev/null +++ b/modules/bigfix/index.html @@ -0,0 +1,569 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Lastpass — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Lastpass

+

The BigFix module has the following coverage:

+
    +
  • Computers

  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/bigfix/schema.html b/modules/bigfix/schema.html new file mode 100644 index 0000000000..19114c4b6f --- /dev/null +++ b/modules/bigfix/schema.html @@ -0,0 +1,703 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BigFix Schema — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

BigFix Schema

+
+

BigfixComputer

+

Represents a computer tracked by BigFix.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first created this node

lastupdated

Timestamp of the last time the node was updated

id

String. Internal BigFix ID.

activedirectorypath

Example: CN=my-server-2,CN=Computers,DC=example-corp,DC=net

agenttype

Example: Native

agentversion

Version of the BigFix agent. Example: 10.0.7.52

averageevaluationcycle

Example: 106 (integer)

besrelayselectionmethod

Example: Manual

besrootserver

Example: bigfixroot.example.com (0)

bios

String value. Example: 06/25/2021

computername

Example: my-server-2

computertype

Example: Virtual, Physical

cpu

Example: 2300 MHz Xeon Gold 5218

devicetype

Example: Server

dnsname

Example: my-server-2.example.com

enrollmentdatetime

The date time this asset was enrolled in BigFix. Example: 2022-04-06T18:54:01-07:00

ipaddress

Example: 192.168.128.215

ipv6address

Example: fe80:0:0:0:abcd:abcd:abcd:abcd

islocked

Boolean - whether this asset is locked

lastreporttime

Last reported datetime of this asset 2023-04-19T15:55:23Z

locationbyiprange

Example: SF

loggedonuser

Currently logged on username. Example: , bartsimpson

macaddress

Example: 00-50-ab-cd-ab-cd

os

Example: Win2019 10.0.17763.3406 (1809)

providername

Example: VMware, On Premises

ram

Example: 16384 MB

relay

Example: mybigfixrelay.example.com

remotedesktopisenabled

Boolean - whether remote desktop is enabled

subnetaddress

Example: 192.168.128.0

username

Example: , bartsimpson

+
+

Relationships

+
    +
  • A BigfixComputer is a resource of a BigfixRoot.

    +
    (:BigfixRoot)-[:RESOURCE]->(:BigfixComputer)
    +
    +
    +
  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/crowdstrike/config.html b/modules/crowdstrike/config.html new file mode 100644 index 0000000000..5b170e8203 --- /dev/null +++ b/modules/crowdstrike/config.html @@ -0,0 +1,575 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Crowdstrike Configuration — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Crowdstrike Configuration

+

Follow these steps to analyze Crowdstrike falcon objects in Cartography.

+
    +
  1. Prepare an API key for crowdstrike falcon

    +
      +
    1. Crowdstrike’s documentation is private, so please see your instance’s documentation on how to generate an API key.

    2. +
    3. Populate an environment variable with the Client ID. You can pass the environment variable name via CLI with the --crowdstrike-client-id-env-var parameter.

    4. +
    5. Populate an environment variable with the Client Secret. You can pass the environment variable name via CLI with the --crowdstrike-client-secret-env-var parameter.

    6. +
    7. If you are using a self-hosted version of crowdstrike, you can change the API url, by passing it into the CLI with the --crowdstrike-api-url parameter.

    8. +
    +
  2. +
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/crowdstrike/index.html b/modules/crowdstrike/index.html new file mode 100644 index 0000000000..0d473159b2 --- /dev/null +++ b/modules/crowdstrike/index.html @@ -0,0 +1,571 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Crowdstrike — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Crowdstrike

+

The crowdstrike module has the following coverage:

+
    +
  • Hosts

  • +
  • Spotlight Vulnerabilities

  • +
  • CVEs

  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/crowdstrike/schema.html b/modules/crowdstrike/schema.html new file mode 100644 index 0000000000..512ad10b07 --- /dev/null +++ b/modules/crowdstrike/schema.html @@ -0,0 +1,855 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Crowdstrike Schema — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+ +
+
+ +
+
+ +
+

Crowdstrike Schema

+
+

CrowdstrikeHost

+

Representation of a Crowdstrike Host

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The device ID for this host

cid

The customer ID

instance_id

The AWS instance ID associated with this host

status

Containment Status of the machine. “Normal” denotes good operations; other values might mean reduced functionality or support.

hostname

The name of the machine.

machine_domain

Active Directory domain name.

crowdstrike_first_seen

Timestamp of device’s first connection to Falcon

crowdstrike_last_seen

Timestamp of device’s most recent connection to Falcon

local_ip

The device’s local IP address.

external_ip

External IP of the device, as seen by CrowdStrike.

cpu_signature

The CPU signature of the device.

bios_manufacturer

Bios manufacture name.

bios_version

Bios version.

mac_address

The MAC address of the device

os_version

Operating system version.

os_build

The build of the OS

platform_id

CrowdStrike agent configuration notes

platform_name

Operating system platform.

service_provider

The service provider for the device.

service_provider_account_id

The service provider account ID associated with this device

agent_version

CrowdStrike agent configuration notes

system_manufacturer

Name of system manufacturer

system_product_name

Name of system product

product_type

The product type

product_type_desc

Name of product type.

provision_status

The provision status of the device

reduced_functionality_mode

Reduced functionality mode (RFM) status

kernel_version

Kernel version of the host OS.

major_version

Major version of the Operating System

minor_version

Minor version of the Operating System

tags

Grouping tags for the device

modified_timestamp

The last time that the machine record was updated. Can include status like containment status changes or configuration group changes

+
+

Relationships

+
    +
  • CrowdstrikeHost has SpotlightVulnerability

    +
    (CrowdstrikeHost)-[HAS_VULNERABILITY]->(SpotlightVulnerability)
    +
    +
    +
  • +
+
+
+
+

SpotlightVulnerability

+

Representation of a Crowdstrike Vulnerability

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID for this vulnerability

cid

The customer ID

aid

The unique identifier (agent ID) of the sensor where the vulnerability was found.

status

The vulnerability’s current status. One of open, closed, reopen, or expired.

created_timestamp

The UTC date and time that the vulnerability was created in Spotlight.

closed_timestamp

The date and time a vulnerability was set to a status of “closed”

updated_timestamp

The UTC date and time of the last update made on a vulnerability.

cve_id

The ID of the CVE.

host_info_local_ip

The device’s local IP address.

remediation_ids

The unique IDs of the remediations.

app_product_name_version

The name and version of the product associated with the vulnerability.

+
+

Relationships

+
    +
  • CrowdstrikeHost has SpotlightVulnerability

    +
    (CrowdstrikeHost)-[HAS_VULNERABILITY]->(SpotlightVulnerability)
    +
    +
    +
  • +
  • SpotlightVulnerability has CVE

    +
    (SpotlightVulnerability)-[HAS_CVE]->(CVE)
    +
    +
    +
  • +
+
+
+
+

CVE::CrowdstrikeFinding

+

Representation of a CVE

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID for this CVE

base_score

Base score of the CVE (float value between 1 and 10).

severity

Severity of the CVE. One of CRITICAL, HIGH, MEDIUM, LOW, UNKNOWN, or NONE.

exploitability_score

Numeric value of the most severe known exploit. 0=UNPROVEN; 30=AVAILABLE; 60=EASILY_ACCESSIBLE; 90=ACTIVELY_USED

+
+

Relationships

+
    +
  • SpotlightVulnerability has CVE

    +
    (SpotlightVulnerability)-[HAS_CVE]->(CVE)
    +
    +
    +
  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/crxcavator/config.html b/modules/crxcavator/config.html new file mode 100644 index 0000000000..b1c5ec2f26 --- /dev/null +++ b/modules/crxcavator/config.html @@ -0,0 +1,578 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Crxcavator Configuration — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Crxcavator Configuration

+

Follow these steps to analyze Chrome Extensions with Cartography.

+
    +
  1. Prepare your CRXcavator API key

    +
      +
    1. Generate an API key from your CRXcavator user page

    2. +
    3. Add the required commandline arguments when calling Cartography

      +
        +
      1. --crxcavator-api-base-url - the full URL to the CRXcavator API. https://api.crxcavator.io/v1 as of 01/16/2020 (this value will be used if not provided)

      2. +
      3. --crxcavator-api-key-env-var - Name of environment variable holding your API key generated in the previous step. Note this is a credential and should be stored in an appropriate secret store to be populated securely into your runtime environment.

      4. +
      +
    4. +
    +
  2. +
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/crxcavator/index.html b/modules/crxcavator/index.html new file mode 100644 index 0000000000..e43bf8c8d9 --- /dev/null +++ b/modules/crxcavator/index.html @@ -0,0 +1,570 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Duo CRXcavator — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Duo CRXcavator

+

The crxcavator module has the following coverage:

+
    +
  • Chrome extensions

  • +
  • GSuite users

  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/crxcavator/schema.html b/modules/crxcavator/schema.html new file mode 100644 index 0000000000..93b0a43372 --- /dev/null +++ b/modules/crxcavator/schema.html @@ -0,0 +1,759 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Crxcavtor Schema — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Crxcavtor Schema

+
+

GSuiteUser

+

Placeholder representation of a single G Suite user object. This node is the minimal data necessary to map who has extensions installed until full G Suite data is imported.

+ ++++ + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The user’s email address, will change to actual G Suite id in future

email

The user’s email address

+
+

Relationships

+
    +
  • GSuiteUsers install ChromeExtensions.

    +
    (GSuiteUser)-[INSTALLS]->(ChromeExtension)
    +
    +
    +
  • +
+
+
+
+

ChromeExtension

+
+

Representation of a CRXcavator Chrome Extension Report.

+
+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The combined extension name and version e.g. "Docs|1.0"

extension_id

CRXcavator id for extension.

version

The versions of the extension in this report

risk_total

CRXcavator risk score for the extension

risk_metadata

Additional data provided by CRXcavator on the risk score

risk_permissions_score

Sum of the permissions component of the risk score

risk_webstore_score

Sum of the webstore component of the risk score

risk_csp_score

Sum of the CSP component of the risk score

risk_optional_permissions_score

Sum of the optional permissions component of the risk score

risk_extcalls_score

Sum of the external calls component of the risk score

risk_vuln_score

Sum of the RetireJS vulnerability component of the risk score

address

Physical address of extension developer

email

Email address of extension developer

icon

URL of the extension icon

crxcavator_last_updated

Date the extension was last updated in the webstore

name

Full name of the extension

offered_by

Name of the extension developer

permissions_warnings

Concatenated list of permissions warnings for the extension

privacy_policy

URL of privacy policy for extension

rating

Current webstore rating for extension

rating_users

How many users have provided a rating for the extension

short_description

Summary of what extension does

size

Size of extension download

support_site

URL of developer support site

users

Webstore count of extension users

website

Developer URL for extension

type

Extension categorization

price

Extension price in webstore if applicable

report_link

URL of full extension report on crxcavator.io

+
+

Relationships

+
    +
  • GSuiteUsers install ChromeExtensions.

    +
    (GSuiteUser)-[INSTALLS]->(ChromeExtension)
    +
    +
    +
  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/cve/config.html b/modules/cve/config.html new file mode 100644 index 0000000000..f58879912a --- /dev/null +++ b/modules/cve/config.html @@ -0,0 +1,569 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CVE Configuration — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

CVE Configuration

+

Follow these steps to analyze CVE objects with Cartography.

+
    +
  1. Call cartography with the --enable-cve flag.

  2. +
  3. If you are mirroring the CVE data, and wish to change the base url, you can pass the base url into the cli with the --nist-cve-url flag.

  4. +
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/cve/index.html b/modules/cve/index.html new file mode 100644 index 0000000000..65a2eeb90a --- /dev/null +++ b/modules/cve/index.html @@ -0,0 +1,569 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CVE — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

CVE

+

The CVE module has the following coverage:

+
    +
  • CVE data, as defined by the v4 JSON CVE format

  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/cve/schema.html b/modules/cve/schema.html new file mode 100644 index 0000000000..7863cc4f6d --- /dev/null +++ b/modules/cve/schema.html @@ -0,0 +1,673 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CVE Schema — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

CVE Schema

+
+

CVE

+

Representation of a CVE

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The CVE ID

assigner

The assigner of the CVE (email address)

description_en

The english description of the issue.

references

This is reference data in the form of URLs

problem_types

A list of CWE identifiers

vector_string

The CVSSv3 scoring data.

attack_vector

The attack vector

attack_complexity

The attack complexity

privileges_required

The privileges required

user_interaction

The user interaction

scope

The scope

confidentiality_impact

The confidentiality impact

integrity_impact

The integrity impact

availability_impact

The availability impact

base_score

The CVSSv3 score

base_severity

The severity

exploitability_score

The exploitability score

impact_score

The impact score

published_date

The date the CVE was published

last_modified_date

The date the CVE was last updated

+
+

Relationships

+

None

+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/digitalocean/config.html b/modules/digitalocean/config.html new file mode 100644 index 0000000000..4bf8524757 --- /dev/null +++ b/modules/digitalocean/config.html @@ -0,0 +1,579 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Configuration — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Configuration

+

Follow these steps to analyze GitHub repos and other objects with Cartography.

+
    +
  1. Prepare your DigitalOcean credentials. Visit official docs for +more up to date info.

    +
      +
    1. Login into your DigitalOcean Account

    2. +
    3. Visit Account -> API -> Tokens section

    4. +
    5. Click on Generate New Token to create a personal access token

    6. +
    7. Make sure the scope of the token is set to READ

    8. +
    +
  2. +
  3. Populate an environment variable of your choice with the access token generated in the previous step.

  4. +
  5. Call the cartography CLI with --digitalocean-token-env-var YOUR_ENV_VAR_HERE.

  6. +
  7. Cartography will then load your graph with data from the account linked to the token you specified.

  8. +
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/digitalocean/index.html b/modules/digitalocean/index.html new file mode 100644 index 0000000000..013375bf65 --- /dev/null +++ b/modules/digitalocean/index.html @@ -0,0 +1,571 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DigitalOcean — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

DigitalOcean

+

The digitalocean module has the following coverage:

+
    +
  • Accounts

  • +
  • Projects

  • +
  • Compute - Droplets

  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/digitalocean/schema.html b/modules/digitalocean/schema.html new file mode 100644 index 0000000000..98ea948bd5 --- /dev/null +++ b/modules/digitalocean/schema.html @@ -0,0 +1,802 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DigitalOcean Schema — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

DigitalOcean Schema

+
+

DOAccount

+

Representation of a DigitalOcean Account object.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The UUID of the account

uuid

The UUID of the account (same value as id)

droplet_limit

Total number of droplets that the account can have at one time

floating_ip_limit

Total number of floating IPs the account may have

status

Status of the account

+
+

Relationships

+
    +
  • DOAccount contains DOProjects.

    +
    (DOAccount)-[RESOURCE]->(DOProjects)
    +
    +
    +
  • +
+
+
+
+

DOProject

+

Representation of a DigitalOcean Project object.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The unique universal identifier of the project

account_id

Id of the DOAccount where this project belongs to

description

The description of the project

environment

The environment of the project’s resources

is_default

If true, all resources will be added to this project if no project is specified

name

The human-readable name for the project

owner_uuid

The unique universal identifier of the project’s owner

created_at

A time value given in ISO8601 combined date and time format that represents when the project was created

updated_at

A time value given in ISO8601 combined date and time format that represents when the project was updated

+
+

Relationships

+
    +
  • DOProject has DODroplets as resource.

    +
    (DOProject)-[RESOURCE]->(DODroplet)
    +
    +
    +
  • +
+
+
+
+

DODroplet

+

Representation of a DigitalOcean Droplet object.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

A unique identifier for each Droplet instance

account_id

Id of the DOAccount where this Droplet belongs to

features

An array of features enabled on this Droplet

locked

A boolean value indicating whether the Droplet has been locked, preventing actions by users

image

The slug of the base image used to create the Droplet instance

ip_address

The v4 external ip address of this Droplet

ip_v6_address

The v6 external ip address of this Droplet

kernel

The current kernel image id

name

The human-readable name set for the Droplet instance

private_ip_address

The v4 internal ip address of this Droplet

project_id

Id of the DOProject where this Droplet belongs to

region

The region that the Droplet instance is deployed in

size

The current size object describing the Droplet

status

A status string indicating the state of the Droplet instance.This may be “new”, “active”, “off”, or “archive”

tags

An array of Tags the Droplet has been tagged with

volumes

A flat array including the unique identifier for each Block Storage volume attached to the Droplet

created_at

A time value given in ISO8601 combined date and time format that represents when the Droplet was created

+
+

Relationships

+
    +
  • DODroplet is a resource of a DOProject.

    +
    (DODroplet)<-[RESOURCE]-(DOProject)
    +
    +
    +
  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/duo/config.html b/modules/duo/config.html new file mode 100644 index 0000000000..ab23ba6822 --- /dev/null +++ b/modules/duo/config.html @@ -0,0 +1,571 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Duo Configuration — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Duo Configuration

+

Follow these steps to analyze Duo objects with Cartography.

+
    +
  1. Prepare a admin api creds.

  2. +
  3. Pass the Duo api host name to the --duo-api-hostname CLI arg.

  4. +
  5. Populate environment variables with the api key and api secret.

  6. +
  7. Pass that those var names to the --duo-api-key-env-var and --duo-api-secret-env-var CLI args.

  8. +
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/duo/index.html b/modules/duo/index.html new file mode 100644 index 0000000000..006db4dddc --- /dev/null +++ b/modules/duo/index.html @@ -0,0 +1,571 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Duo — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Duo

+

The okta module has the following coverage:

+
    +
  • Users

  • +
  • Groups

  • +
  • Endpoints

  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/duo/schema.html b/modules/duo/schema.html new file mode 100644 index 0000000000..eb601e8206 --- /dev/null +++ b/modules/duo/schema.html @@ -0,0 +1,1242 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Duo Schema — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Duo Schema

+
+

DuoApiHost

+

Represents a Duo API Host to conain Duo resources.

+ ++++ + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The hostname

+
+

Relationships

+
    +
  • An DuoApiHost contains DuoUsers

    +
    (DuoApiHost)-[RESOURCE]->(DuoUser)
    +
    +
    +
  • +
  • An DuoApiHost contains DuoGroups

    +
    (DuoApiHost)-[RESOURCE]->(DuoGroup)
    +
    +
    +
  • +
  • An DuoApiHost contains DuoEndpoints

    +
    (DuoApiHost)-[RESOURCE]->(DuoEndpoint)
    +
    +
    +
  • +
  • An DuoApiHost contains DuoPhones

    +
    (DuoApiHost)-[RESOURCE]->(DuoPhone)
    +
    +
    +
  • +
  • An DuoApiHost contains DuoTokens

    +
    (DuoApiHost)-[RESOURCE]->(DuoToken)
    +
    +
    +
  • +
  • An DuoApiHost contains DuoWebAuthnCredentials

    +
    (DuoApiHost)-[RESOURCE]->(DuoWebAuthnCredential)
    +
    +
    +
  • +
+
+
+
+

DuoGroup

+

Represents a group in Duo.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The user_id

desc

The group’s description.

group_id

The group’s ID.

mobile_otp_enabled

Legacy parameter; no effect if specified and always returns false.

name

The group’s name. If managed by directory sync, then the name returned here also indicates the source directory.

push_enabled

Legacy parameter; no effect if specified and always returns false.

sms_enabled

Legacy parameter; no effect if specified and always returns false

status

The group’s authentication status. May be one of: “Active”, “Bypass”, “Disabled”

voice_enabled

Legacy parameter; no effect if specified and always returns false

+
+

Relationships

+
    +
  • An DuoApiHost contains DuoGroups

    +
    (DuoApiHost)-[RESOURCE]->(DuoGroup)
    +
    +
    +
  • +
  • A DuoUser is part of multiple DuoGroups.

    +
    (DuoUser)-[MEMBER_OF_DUO_GROUP]->(DuoGroup)
    +
    +
    +
  • +
+
+
+
+

DuoUser

+

Represents a user in Duo.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The user_id

alias1

The user’s username alias1.

alias2

The user’s username alias2.

alias3

The user’s username alias3.

alias4

The user’s username alias4.

aliases

Map of the user’s username alias(es). Up to eight aliases may exist.

created

The user’s creation date as a UNIX timestamp.

email

The user’s email address.

firstname

The user’s given name.

groups

List of groups to which this user belongs. See Retrieve Groups for response info.

is_enrolled

Is true if the user has a phone, hardware token, U2F token, WebAuthn security key, or other WebAuthn method available for authentication. Otherwise, false.

last_directory_sync

An integer indicating the last update to the user via directory sync as a Unix timestamp, or null if the user has never synced with an external directory or if the directory that originally created the user has been deleted from Duo.

last_login

An integer indicating the last time this user logged in, as a Unix timestamp, or null if the user has not logged in.

lastname

The user’s surname.

notes

Notes about this user. Viewable in the Duo Admin Panel.

realname

The user’s real name (or full name).

status

The user’s status. One of: “active”, “bypass”, “disabled”, “locked out”, “pending deletion”.

tokens

A list of tokens that this user can use. A list of JSON strings

u2f_tokens

A list of U2F tokens that this user can use. A list of JSON strings

user_id

The user’s ID.

username

The user’s username.

webauthncredentials

A list of WebAuthn authenticators that this user can use. A list of JSON strings

+
+

Relationships

+
    +
  • An DuoApiHost contains DuoUsers

    +
    (DuoApiHost)-[RESOURCE]->(DuoUser)
    +
    +
    +
  • +
  • A DuoUser is part of multiple DuoGroups.

    +
    (DuoUser)-[MEMBER_OF_DUO_GROUP]->(DuoGroup)
    +
    +
    +
  • +
  • A DuoUser has multiple DuoEndpoints

    +
    (DuoUser)-[HAS_DUO_ENDPOINT]->(DuoEndpoint)
    +
    +
    +
  • +
  • A DuoUser has multiple DuoPhones

    +
    (DuoUser)-[HAS_DUO_PHONE]->(DuoPhone)
    +
    +
    +
  • +
  • A DuoUser has multiple DuoTokens

    +
    (DuoUser)-[HAS_DUO_TOKEN]->(DuoToken)
    +
    +
    +
  • +
  • A DuoUser has multiple WebAuthnCredentials

    +
    (DuoUser)-[HAS_DUO_WEB_AUTHN_CREDENTIAL]->(WebAuthnCredential)
    +
    +
    +
  • +
  • A DuoUser is an identity to a Human

    +
    (DuoUser)<-[IDENTITY_DUO]-(Human)
    +
    +
    +
  • +
+
+
+
+

DuoEndpoint

+

Represents a endpoint in Duo.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The epkey

browsers

Collected information about all detected browsers on an individual endpoint. A list of JSON strings

computer_sid

The machine security identifier of a Windows endpoint.

cpu_id

The CPU ID of a Windows endpoint.

device_id

Custom device identifier of a Meraki-managed iOS endpoint. Returned for Duo Premier customers only.

device_identifier

The unique device attribute value that identifies the endpoint. Returned for Duo Premier customers only. This property will be deprecated in a future release.

device_identifier_type

The device attribute used to identify a unique endpoint. One of “hardware_uuid”, “fqdn”, “hardware_serial”, “device_udid”, or none. This property will be deprecated in a future release.

device_name

The endpoint’s hostname.

device_udid

The unique device identifier for iOS endpoints managed by Workspace ONE, MobileIron Cloud or Core, or Sophos Mobile via certificates. Returned for Duo Premier customers only.

device_username

The unique attribute value that identifies the endpoint’s associated user in the management system. Returned for Duo Premier customers only.

device_username_type

The management system attribute used to identify the user associated with the unique endpoint. One of “os_username”, “upn”, “username”, “email”, or none. Returned for Duo Premier customers only.

disk_encryption_status

The hard drive encryption status of the endpoint as detected by the Duo Device Health app. One of “On”, “Off”, or “Unknown”.

domain_sid

The Active Directory domain security identifier for a domain-joined Windows endpoint. Empty if the Windows endpoint is not joined to a domain.

email

The email address, if present, of the user associated with an endpoint.

epkey

The endpoint’s unique identifier.

firewall_status

Status of the endpoint’s local firewall as detected by the Duo Device Health app. One of “On”, “Off”, or “Unknown”.

hardware_uuid

The universally unique identifier for a Mac endpoint.

health_app_client_version

The version of the Duo Device Health app installed on the endpoint.

health_data_last_collected

The last time the Duo Device Health app performed a device health check, as a Unix timestamp.

last_updated

The last time the endpoint accessed Duo, as a Unix timestamp.

machine_guid

The globally unique identifier for a Windows endpoint.

model

The device model of a 2FA endpoint.

os_build

The endpoint’s operating system build number.

os_family

The endpoint’s operating system platform.

os_version

The endpoint’s operating system version.

password_status

Whether the local admin password is set on the endpoint as detected by the Duo Device Health app. One of “Set”, “Unset”, or “Unknown”

security_agents

Information about security agents present on the endpoint as detected by the Duo Device Health app. Returned for Duo Premier customers only. a list of JSON strings

trusted_endpoint

Whether the endpoint is a Duo managed endpoint. One of “yes”, “no”, or “unknown”. Returned for Duo Premier customers only.

type

The endpoint’s device class.

username

The Duo username of the user associated with an endpoint.

+
+

Relationships

+
    +
  • An DuoApiHost contains DuoEndpoints

    +
    (DuoApiHost)-[RESOURCE]->(DuoEndpoint)
    +
    +
    +
  • +
  • A DuoUser has multiple DuoEndpoints

    +
    (DuoUser)-[HAS_DUO_ENDPOINT]->(DuoEndpoint)
    +
    +
    +
  • +
+
+
+
+

DuoPhone

+

Represents a phone in Duo.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The phone_id

activated

Has this phone been activated for Duo Mobile yet? Either true or false.

capabilities

List of strings, each a factor that can be used with the device. Any of “auto”, “push”, “pphone”, “sms”, “mobile_otp”

encrypted

The encryption status of an Android or iOS device file system. One of: “Encrypted”, “Unencrypted”, or “Unknown”. Blank for other platforms.

extension

An extension, if necessary.

fingerprint

Whether an Android or iOS phone is configured for biometric verification. One of: “Configured”, “Disabled”, or “Unknown”. Blank for other platforms.

last_seen

An integer indicating the timestamp of the last contact between Duo’s service and the activated Duo Mobile app installed on the phone. Blank if the device has never activated Duo Mobile or if the platform does not support it.

model

The phone’s model.

name

Free-form label for the phone.

phone_id

The phone’s ID.

platform

The phone platform. One of: “unknown”, “google android”, “apple ios”, “windows phone 7”, “rim blackberry”, “java j2me”, “palm webos”, “symbian os”, “windows mobile”, or “generic smartphone”

postdelay

The time (in seconds) to wait after the extension is dialed and before the speaking the prompt.

predelay

The time (in seconds) to wait after the number picks up and before dialing the extension.

screenlock

Whether screen lock is enabled on an Android or iOS phone. One of: “Locked”, “Unlocked”, or “Unknown”. Blank for other platforms.

sms_passcodes_sent

Have SMS passcodes been sent to this phone? Either true or false.

tampered

Whether an iOS or Android device is jailbroken or rooted. One of: “Not Tampered”, “Tampered”, or “Unknown”. Blank for other platforms.

type

The type of phone. One of: “unknown”, “mobile”, or “landline”.

+
+

Relationships

+
    +
  • An DuoApiHost contains DuoPhone

    +
    (DuoApiHost)-[RESOURCE]->(DuoPhone)
    +
    +
    +
  • +
  • A DuoUser has multiple DuoPhones

    +
    (DuoUser)-[HAS_DUO_PHONE]->(DuoPhone)
    +
    +
    +
  • +
+
+
+
+

DuoToken

+

Represents a token in Duo.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The token_id

admins

A list of administrators associated with this hardware token. See Retrieve Administrators for descriptions of the response fields. A list of JSON strings

serial

The serial number of the hardware token; used to uniquely identify the hardware token when paired with type.

token_id

The hardware token’s unique ID.

totp_step

Value is null for all supported token types.

type

The type of hardware token.

+
+

Relationships

+
    +
  • An DuoApiHost contains DuoTokens

    +
    (DuoApiHost)-[RESOURCE]->(DuoToken)
    +
    +
    +
  • +
  • A DuoUser has multiple DuoTokens

    +
    (DuoUser)-[HAS_DUO_TOKEN]->(DuoToken)
    +
    +
    +
  • +
+
+
+
+

DuoWebAuthnCredential

+

Represents a web authn credential in Duo.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The webauthnkey

admin

Selected information about the administrator attached to the WebAuthn credential. Returns null if attached to an end user. Not returned if the API application does not have sufficient permission to manage administrators. A JSON string

credential_name

Free-form label for the WebAuthn credential.

date_added

The date the WebAuthn credential was registered in Duo.

label

Indicates the type of WebAuthn credential. One of: “Security Key” or “Touch ID”. Present when attached to a user.

webauthnkey

The WebAuthn credential’s registration identifier.

+
+

Relationships

+
    +
  • An DuoApiHost contains DuoWebAuthnCredentials

    +
    (DuoApiHost)-[RESOURCE]->(DuoWebAuthnCredential)
    +
    +
    +
  • +
  • A DuoUser has multiple DuoWebAuthnCredentials

    +
    (DuoUser)-[HAS_DUO_WEB_AUTHN_CREDENTIAL]->(DuoWebAuthnCredential)
    +
    +
    +
  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/gcp/config.html b/modules/gcp/config.html new file mode 100644 index 0000000000..dbb62c576f --- /dev/null +++ b/modules/gcp/config.html @@ -0,0 +1,604 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GCP Configuration — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

GCP Configuration

+

Follow these steps to analyze GCP projects with Cartography.

+
    +
  1. Prepare your GCP credential(s).

    +
      +
    1. Create an identity - either a User Account or a Service Account - for Cartography to run as

    2. +
    3. Ensure that this identity has the following roles (https://cloud.google.com/iam/docs/understanding-roles) attached to it:

      +
        +
      • roles/iam.securityReviewer

      • +
      • roles/resourcemanager.organizationViewer: needed to list/get GCP Organizations

      • +
      • roles/resourcemanager.folderViewer: needed to list/get GCP Folders

      • +
      +
    4. +
    5. Ensure that the machine you are running Cartography on can authenticate to this identity.

      +
        +
      • Method 1: You can do this by setting your GOOGLE_APPLICATION_CREDENTIALS environment variable to point to a json file containing your credentials. As per SecurityCommonSense™️, please ensure that only the user account that runs Cartography has read-access to this sensitive file.

      • +
      • Method 2: If you are running Cartography on a GCE instance or other GCP service, you can make use of the credential management provided by the default service accounts on these services. See the official docs on Application Default Credentials for more details.

      • +
      +
    6. +
    +
  2. +
+
+

Multiple GCP Project Setup

+

In order for Cartography to be able to pull all assets from all GCP Projects within an Organization, the User/Service Account assigned to Cartography needs to be created at the Organization level. +This is because IAM access control policies applied on the Organization resource apply throughout the hierarchy on all resources in the organization.

+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/gcp/index.html b/modules/gcp/index.html new file mode 100644 index 0000000000..fb282ac6ab --- /dev/null +++ b/modules/gcp/index.html @@ -0,0 +1,573 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Google Cloud Compute (GCP) — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Google Cloud Compute (GCP)

+

The gcp module has the following coverage:

+
    +
  • Cloud Resource Manager

  • +
  • Compute

  • +
  • DNS

  • +
  • Storage

  • +
  • Google Kubernetes Engine

  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/gcp/schema.html b/modules/gcp/schema.html new file mode 100644 index 0000000000..80dfc6be08 --- /dev/null +++ b/modules/gcp/schema.html @@ -0,0 +1,1944 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GCP Schema — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+ + +
+
+ +
+

GCP Schema

+
+

GCPOrganization

+

Representation of a GCP Organization object.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The name of the GCP Organization, e.g. “organizations/1234”

displayname

The “friendly name”, e.g. “My Company”

lifecyclestate

The organization’s current lifecycle state. Assigned by the server. See the official docs.

+
+

Relationships

+
    +
  • GCPOrganizations contain GCPFolders.

    +
    (GCPOrganization)-[RESOURCE]->(GCPFolder)
    +
    +
    +
  • +
  • GCPOrganizations can contain GCPProjects.

    +
    (GCPOrganization)-[RESOURCE]->(GCPProjects)
    +
    +
    +
  • +
+
+
+
+

GCPFolder

+
+

Representation of a GCP Folder. An additional helpful reference is the Google Compute Platform resource hierarchy.

+
+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The name of the folder, e.g. “folders/1234”

displayname

A friendly name of the folder, e.g. “My Folder”.

lifecyclestate

The folder’s current lifecycle state. Assigned by the server. See the official docs.

+
+

Relationships

+
    +
  • GCPOrganizations are parents of GCPFolders.

    +
    (GCPOrganization)<-[PARENT]-(GCPFolder)
    +
    +
    +
  • +
  • GCPFolders can contain GCPProjects

    +
    (GCPFolder)-[RESOURCE]->(GCPProject)
    +
    +
    +
  • +
  • GCPFolders can contain other GCPFolders.

    +
    (GCPFolder)-[RESOURCE]->(GCPFolder)
    +
    +
    +
  • +
+
+
+
+

GCPProject

+
+

Representation of a GCP Project. An additional helpful reference is the Google Compute Platform resource hierarchy.

+
+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the project, e.g. “sys-12345”

projectnumber

The number uniquely identifying the project, e.g. ‘987654’

displayname

A friendly name of the project, e.g. “MyProject”.

lifecyclestate

The project’s current lifecycle state. Assigned by the server. See the official docs.

+
+
+

Relationships

+
    +
  • GCPOrganizations contain GCPProjects.

    +
    (GCPOrganization)-[RESOURCE]->(GCPProjects)
    +
    +
    +
      +
    • GCPFolders can contain GCPProjects

      +
      (GCPFolder)-[RESOURCE]->(GCPProject)
      +
      +
      +
    • +
    +
  • +
  • GCPVpcs are part of GCPProjects

    +
    (GCPProject)-[RESOURCE]->(GCPVpc)
    +
    +
    +
  • +
+
+
+

GCPBucket

+

Representation of a GCP Storage Bucket.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the storage bucket, e.g. “bucket-12345”

projectnumber

The number uniquely identifying the project associated with the storage bucket, e.g. ‘987654’

self_link

The URI of the storage bucket

kind

The kind of item this is. For storage buckets, this is always storage#bucket

location

The location of the bucket. Object data for objects in the bucket resides in physical storage within this region. Defaults to US. See Cloud Storage bucket locations for the authoritative list.

location_type

The type of location that the bucket resides in, as determined by the location property

meta_generation

The metadata generation of this bucket

storage_class

The bucket’s default storage class, used whenever no storageClass is specified for a newly-created object. For more information, see storage classes

time_created

The creation time of the bucket in RFC 3339 format

retention_period

The period of time, in seconds, that objects in the bucket must be retained and cannot be deleted, overwritten, or archived

iam_config_bucket_policy_only

The bucket’s Bucket Policy Only configuration

owner_entity

The entity, in the form project-owner-projectId

owner_entity_id

The ID for the entity

versioning_enabled

The bucket’s versioning configuration (if set to True, versioning is fully enabled for this bucket)

log_bucket

The destination bucket where the current bucket’s logs should be placed

requester_pays

The bucket’s billing configuration (if set to true, Requester Pays is enabled for this bucket)

default_kms_key_name

A Cloud KMS key that will be used to encrypt objects inserted into this bucket, if no encryption method is specified

+
+

Relationships

+
    +
  • GCPBuckets are part of GCPProjects.

    +
    (GCPProject)-[RESOURCE]->(GCPBucket)
    +
    +
    +
  • +
  • GCPBuckets can be labelled with GCPBucketLabels.

    +
    (GCPBucket)<-[LABELLED]-(GCPBucketLabels)
    +
    +
    +
  • +
+
+
+
+

GCPDNSZone

+

Representation of a GCP DNS Zone.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

created_at

The date and time the zone was created

description

An optional description of the zone

dns_name

The DNS name of this managed zone, for instance “example.com.”.

firstseen

Timestamp of when a sync job first discovered this node

id

Unique identifier

name

The name of the zone

nameservers

Virtual name servers the zone is delegated to

visibility

The zone’s visibility: public zones are exposed to the Internet, while private zones are visible only to Virtual Private Cloud resources.

+
+

Relationships

+
    +
  • GKEClusters are resources of GCPProjects.

    +
    (GCPProject)-[RESOURCE]->(GCPDNSZone)
    +
    +
    +
  • +
+
+
+
+

Label: GCPBucketLabel

+

Representation of a GCP Storage Bucket Label. This node contains a key-value pair.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the bucket label. Takes the form “GCPBucketLabel_{key}.”

key

The key of the bucket label.

value

The value of the bucket label.

+
    +
  • GCPBuckets can be labeled with GCPBucketLabels.

    +
    (GCPBucket)<-[LABELED]-(GCPBucketLabels)
    +
    +
    +
  • +
+
+
+

GCPInstance

+

Representation of a GCP Instance. Additional references can be found in the official documentation.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The partial resource URI representing this instance. Has the form projects/{project_name}/zones/{zone_name}/instances/{instance_name}.

partial_uri

Same as id above.

self_link

The full resource URI representing this instance. Has the form https://www.googleapis.com/compute/v1/{partial_uri}

instancename

The name of the instance, e.g. “my-instance”

zone_name

The zone that the instance is installed on

hostname

If present, the hostname of the instance

exposed_internet

Set to True with exposed_internet_type = 'direct' if there is an ‘allow’ IPRule attached to one of the instance’s ingress firewalls with the following conditions: The ‘allow’ IpRule allows traffic from one or more TCP ports, and the ‘allow’ IpRule is not superceded by a ‘deny’ IPRule (in GCP, a firewall rule of priority 1 gets applied ahead of a firewall rule of priority 100, and ‘deny’ rules of the same priority are applied ahead of ‘allow’ rules)

status

The GCP Instance Lifecycle state of the instance

+
+

Relationships

+
    +
  • GCPInstances are resources of GCPProjects.

    +
    (GCPProject)-[RESOURCE]->(GCPInstance)
    +
    +
    +
  • +
  • GCPNetworkInterfaces are attached to GCPInstances

    +
    (GCPInstance)-[NETWORK_INTERFACE]->(GCPNetworkInterface)
    +
    +
    +
  • +
  • GCP Instances may be members of one or more GCP VPCs.

    +
       (GCPInstance)-[:MEMBER_OF_GCP_VPC]->(GCPVpc)
    +
    +Also note that this relationship is a shortcut for:
    +
    +
    +
    (GCPInstance)-[:NETWORK_INTERFACE]->(:GCPNetworkInterface)-[:PART_OF_SUBNET]->(GCPSubnet)<-[:RESOURCE]-(GCPVpc)
    +
    +
    +
  • +
  • GCP Instances may have GCP Tags defined on them for use in network firewall routing.

    +
    (GCPInstance)-[:TAGGED]->(GCPNetworkTag)
    +
    +
    +
  • +
  • GCP Firewalls allow ingress to GCP instances.

    +
       (GCPFirewall)-[:FIREWALL_INGRESS]->(GCPInstance)
    +
    +Note that this relationship is a shortcut for:
    +
    +
    +
       (vpc:GCPVpc)<-[MEMBER_OF_GCP_VPC]-(GCPInstance)-[TAGGED]->(GCPNetworkTag)-[TARGET_TAG]-(GCPFirewall{direction: 'INGRESS'})<-[RESOURCE]-(vpc)
    +
    +as well as
    +
    +
    +
    MATCH (fw:GCPFirewall{direction: 'INGRESS', has_target_service_accounts: False}})
    +WHERE NOT (fw)-[TARGET_TAG]->(GCPNetworkTag)
    +MATCH (GCPInstance)-[MEMBER_OF_GCP_VPC]->(GCPVpc)-[RESOURCE]->(fw)
    +
    +
    +
  • +
+
+
+
+

GCPNetworkTag

+

Representation of a Tag defined on a GCP Instance or GCP Firewall. Tags are defined on GCP instances for use in network firewall routing.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

GCP doesn’t define a resource URI for Tags so we define this as {instance resource URI}/tags/{tag value}

tag_id

same as id

value

The actual value of the tag

+
+

Relationships

+
    +
  • GCP Instances can be labeled with tags.

    +
    (GCPInstance)-[:TAGGED]->(GCPNetworkTag)
    +
    +
    +
  • +
  • GCP Firewalls can be labeled with tags to direct traffic to or deny traffic to labeled GCPInstances

    +
    (GCPFirewall)-[:TARGET_TAG]->(GCPNetworkTag)
    +
    +
    +
  • +
  • GCPNetworkTags are defined on a VPC and only have effect on assets in that VPC

    +
    (GCPVpc)-[DEFINED_IN]->(GCPNetworkTag)
    +
    +
    +
  • +
+
+
+
+

GCPVpc

+

Representation of a GCP VPC. In GCP documentation this is also known simply as a “Network” object.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The partial resource URI representing this VPC. Has the form projects/{project_name}/global/networks/{vpc name}.

partial_uri

Same as id

self_link

The full resource URI representing this VPC. Has the form https://www.googleapis.com/compute/v1/{partial_uri}

name

The name of the VPC

project_id

The project ID that this VPC belongs to

auto_create_subnetworks

When set to true, the VPC network is created in “auto” mode. When set to false, the VPC network is created in “custom” mode. An auto mode VPC network starts with one subnet per region. Each subnet has a predetermined range as described in Auto mode VPC network IP ranges.

routing_confg_routing_mode

The network-wide routing mode to use. If set to REGIONAL, this network’s Cloud Routers will only advertise routes with subnets of this network in the same region as the router. If set to GLOBAL, this network’s Cloud Routers will advertise routes with all subnets of this network, across regions.

description

A description for the VPC

+
+

Relationships

+
    +
  • GCPVpcs are part of projects

    +
    (GCPProject)-[RESOURCE]->(GCPVpc)
    +
    +
    +
  • +
  • GCPVpcs contain GCPSubnets

    +
    (GCPVpc)-[RESOURCE]->(GCPSubnet)
    +
    +
    +
  • +
  • GCPSubnets are part of GCP VPCs

    +
    (GCPVpc)-[RESOURCE]->(GCPSubnet)
    +
    +
    +
  • +
  • GCPNetworkTags are defined on a VPC and only have effect on assets in that VPC

    +
    (GCPVpc)-[DEFINED_IN]->(GCPNetworkTag)
    +
    +
    +
  • +
  • GCP Instances may be members of one or more GCP VPCs.

    +
       (GCPInstance)-[:MEMBER_OF_GCP_VPC]->(GCPVpc)
    +
    +Also note that this relationship is a shortcut for:
    +
    +
    +
    (GCPInstance)-[:NETWORK_INTERFACE]->(:GCPNetworkInterface)-[:PART_OF_SUBNET]->(GCPSubnet)<-[:RESOURCE]-(GCPVpc)
    +
    +
    +
  • +
+
+
+
+

GCPNetworkInterface

+

Representation of a GCP Instance’s network interface (scroll down to the fields on “networkInterface”).

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

A partial resource URI representing this network interface. Note: GCP does not define a partial resource URI for network interfaces, so we create one so we can uniquely identify GCP network interfaces. Has the form projects/{project_name}/zones/{zone_name}/instances/{instance_name}/networkinterfaces/{network interface name}.

nic_id

Same as id

name

The name of the network interface

private_ip

The private IP address of this network interface. This IP is valid on the network interface’s VPC.

+
+

Relationships

+
    +
  • GCPNetworkInterfaces are attached to GCPInstances

    +
    (GCPInstance)-[NETWORK_INTERFACE]->(GCPNetworkInterface)
    +
    +
    +
  • +
  • GCPNetworkInterfaces are connected to GCPSubnets

    +
    (GCPNetworkInterface)-[PART_OF_SUBNET]->(GCPSubnet)
    +
    +
    +
  • +
  • GCPNetworkInterfaces have GCPNicAccessConfig objects defined on them

    +
    (GCPNetworkInterface)-[RESOURCE]->(GCPNicAccessConfig)
    +
    +
    +
  • +
+
+
+
+

GCPNicAccessConfig

+

Representation of the AccessConfig object on a GCP Instance’s network interface (scroll down to the fields on “networkInterface”).

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

A partial resource URI representing this AccessConfig. Note: GCP does not define a partial resource URI for AccessConfigs, so we create one so we can uniquely identify GCP network interface access configs. Has the form projects/{project_name}/zones/{zone_name}/instances/{instance_name}/networkinterfaces/{network interface name}/accessconfigs/{access config type}.

partial_uri

Same as id

type

The type of configuration. GCP docs say: “The default and only option is ONE_TO_ONE_NAT.”

name

The name of this access configuration. The default and recommended name is External NAT, but you can use any arbitrary string, such as My external IP or Network Access.

public_ip

The external IP associated with this instance

set_public_ptr

Specifies whether a public DNS ‘PTR’ record should be created to map the external IP address of the instance to a DNS domain name.

public_ptr_domain_name

The DNS domain name for the public PTR record. You can set this field only if the setPublicPtr field is enabled.

network_tier

This signifies the networking tier used for configuring this access configuration and can only take the following values: PREMIUM, STANDARD.

+
+

Relationships

+
    +
  • GCPNetworkInterfaces have GCPNicAccessConfig objects defined on them

    +
    (GCPNetworkInterface)-[RESOURCE]->(GCPNicAccessConfig)
    +
    +
    +
  • +
+
+
+
+

GCPRecordSet

+

Representation of a GCP Resource Record Set.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

data

Data contained in the record

firstseen

Timestamp of when a sync job first discovered this node

id

Same as name

name

The name of the Resource Record Set

type

The identifier of a supported record type. See the list of Supported DNS record types.

ttl

Number of seconds that this ResourceRecordSet can be cached by resolvers.

+
+

Relationships

+
    +
  • GCPRecordSets are records of GCPDNSZones.

    +
    (GCPDNSZone)-[HAS_RECORD]->(GCPRecordSet)
    +
    +
    +
  • +
+
+
+
+

GCPSubnet

+

Representation of a GCP Subnetwork.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

A partial resource URI representing this Subnet. Has the form projects/{project}/regions/{region}/subnetworks/{subnet name}.

partial_uri

Same as id

self_link

The full resource URI representing this subnet. Has the form https://www.googleapis.com/compute/v1/{partial_uri}

project_id

The project ID that this Subnet belongs to

name

The name of this Subnet

region

The region of this Subnet

gateway_address

Gateway IP address of this Subnet

ip_cidr_range

The CIDR range covered by this Subnet

vpc_partial_uri

The partial URI of the VPC that this Subnet is a part of

private_ip_google_access

Whether the VMs in this subnet can access Google services without assigned external IP addresses. This field can be both set at resource creation time and updated using setPrivateIpGoogleAccess.

+
+

Relationships

+
    +
  • GCPSubnets are part of GCP VPCs

    +
    (GCPVpc)-[RESOURCE]->(GCPSubnet)
    +
    +
    +
  • +
  • GCPNetworkInterfaces are connected to GCPSubnets

    +
    (GCPNetworkInterface)-[PART_OF_SUBNET]->(GCPSubnet)
    +
    +
    +
  • +
+
+
+
+

GCPFirewall

+

Representation of a GCP Firewall.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

A partial resource URI representing this Firewall.

partial_uri

Same as id

direction

Either ‘INGRESS’ for inbound or ‘EGRESS’ for outbound

disabled

Whether this firewall object is disabled

priority

The priority of this firewall rule from 1 (apply this first)-65535 (apply this last)

self_link

The full resource URI to this firewall

has_target_service_accounts

Set to True if this Firewall has target service accounts defined. This field is currently a placeholder for future functionality to add GCP IAM objects to Cartography. If True, this firewall rule will only apply to GCP instances that use the specified target service account.

+
+

Relationships

+
    +
  • Firewalls belong to VPCs

    +
    (GCPVpc)-[RESOURCE]->(GCPFirewall)
    +
    +
    +
  • +
  • Firewalls define rules that allow traffic

    +
    (GcpIpRule)-[ALLOWED_BY]->(GCPFirewall)
    +
    +
    +
  • +
  • Firewalls define rules that deny traffic

    +
    (GcpIpRule)-[DENIED_BY]->(GCPFirewall)
    +
    +
    +
  • +
  • GCP Firewalls can be labeled with tags to direct traffic to or deny traffic to labeled GCPInstances

    +
    (GCPFirewall)-[:TARGET_TAG]->(GCPNetworkTag)
    +
    +
    +
  • +
  • GCP Firewalls allow ingress to GCP instances.

    +
       (GCPFirewall)-[:FIREWALL_INGRESS]->(GCPInstance)
    +
    +Note that this relationship is a shortcut for:
    +
    +
    +
       (vpc:GCPVpc)<-[MEMBER_OF_GCP_VPC]-(GCPInstance)-[TAGGED]->(GCPNetworkTag)-[TARGET_TAG]-(GCPFirewall{direction: 'INGRESS'})<-[RESOURCE]-(vpc)
    +
    +as well as
    +
    +
    +
    MATCH (fw:GCPFirewall{direction: 'INGRESS', has_target_service_accounts: False}})
    +WHERE NOT (fw)-[TARGET_TAG]->(GCPNetworkTag)
    +MATCH (GCPInstance)-[MEMBER_OF_GCP_VPC]->(GCPVpc)-[RESOURCE]->(fw)
    +
    +
    +
  • +
+
+
+
+

GCPForwardingRule

+

Representation of GCP Forwarding Rules and Global Forwarding Rules.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

A partial resource URI representing this Forwarding Rule

partial_uri

Same as id

ip_address

IP address that this Forwarding Rule serves

ip_protocol

IP protocol to which this rule applies

load_balancing_scheme

Specifies the Forwarding Rule type

name

Name of the Forwarding Rule

network

A partial resource URI of the network this Forwarding Rule belongs to

port_range

Port range used in conjunction with a target resource. Only packets addressed to ports in the specified range will be forwarded to target configured

ports

Ports to forward to a backend service. Only packets addressed to these ports are forwarded to the backend services configured

project_id

The project ID that this Forwarding Rule belongs to

region

The region of this Forwarding Rule

self_link

Server-defined URL for the resource

subnetwork

A partial resource URI of the subnetwork this Forwarding Rule belongs to

target

A partial resource URI of the target resource to receive the traffic

+
+

Relationships

+
    +
  • GCPForwardingRules can be a resource of a GCPVpc.

    +
    (GCPVpc)-[RESOURCE]->(GCPForwardingRule)
    +
    +
    +
  • +
  • GCPForwardingRules can be a resource of a GCPSubnet.

    +
    (GCPSubnet)-[RESOURCE]->(GCPForwardingRule)
    +
    +
    +
  • +
+
+
+
+

GKECluster

+

Representation of a GCP GKE Cluster.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

basic_auth

Set to True if both masterauth_username and masterauth_password are set

created_at

The date and time the cluster was created

cluster_ipv4cidr

The IP address range of the container pods in the cluster

current_master_version

The current software version of the master endpoint

database_encryption

Configuration of etcd encryption

description

An optional description of the cluster

endpoint

The IP address of the cluster’s master endpoint. The endpoint can be accessed from the internet at https://username:password@endpoint/

exposed_internet

Set to True if at least among private_nodes, private_endpoint_enabled, or master_authorized_networks are disabled

firstseen

Timestamp of when a sync job first discovered this node

id

Same as self_link

initial_version

The initial Kubernetes version for the cluster

location

The name of the Google Compute Engine zone or region in which the cluster resides

logging_service

The logging service used to write logs. Available options: logging.googleapis.com/kubernetes, logging.googleapis.com, none

master_authorized_networks

If enabled, it disallows all external traffic to access Kubernetes master through HTTPS except traffic from the given CIDR blocks, Google Compute Engine Public IPs and Google Prod IPs

masterauth_username

The username to use for HTTP basic authentication to the master endpoint. For clusters v1.6.0 and later, basic authentication can be disabled by leaving username unspecified (or setting it to the empty string)

masterauth_password

The password to use for HTTP basic authentication to the master endpoint. If a password is provided for cluster creation, username must be non-empty

monitoring_service

The monitoring service used to write metrics. Available options: monitoring.googleapis.com/kubernetes, monitoring.googleapis.com, none

name

The name of the cluster

network

The name of the Google Compute Engine network to which the cluster is connected

network_policy

Set to True if a network policy provider has been enabled

private_endpoint_enabled

Whether the master’s internal IP address is used as the cluster endpoint

private_endpoint

The internal IP address of the cluster’s master endpoint

private_nodes

If enabled, all nodes are given only private addresses and communicate with the master via private networking

public_endpoint

The external IP address of the cluster’s master endpoint

self_link

Server-defined URL for the resource

services_ipv4cidr

The IP address range of the Kubernetes services in the cluster

shielded_nodes

Whether Shielded Nodes are enabled

status

The current status of the cluster

subnetwork

The name of the Google Compute Engine subnetwork to which the cluster is connected

zone

The name of the Google Compute Engine zone in which the cluster resides

+
+

Relationships

+
    +
  • GKEClusters are resources of GCPProjects.

    +
    (GCPProject)-[RESOURCE]->(GKECluster)
    +
    +
    +
  • +
+
+
+
+

IpRule::IpPermissionInbound::GCPIpRule

+

An IpPermissionInbound node is a specific type of IpRule. It represents a generic inbound IP-based rules. The creation of this node is currently derived from ingesting AWS EC2 Security Group rules.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

ruleid

{firewall_partial_uri}/{rule_type}/{port_range}{protocol}

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

protocol

The protocol this rule applies to

fromport

Lowest port in the range defined by this rule

toport

Highest port in the range defined by this rule

+
+

Relationships

+
    +
  • GCP Firewall rules are defined on IpRange objects.

    +
    (GCPIpRule, IpRule, IpPermissionInbound)<-[MEMBER_OF_IP_RULE)-(:IpRange)
    +
    +
    +
  • +
  • Firewalls define rules that allow traffic

    +
    (GcpIpRule)-[ALLOWED_BY]->(GCPFirewall)
    +
    +
    +
  • +
  • Firewalls define rules that deny traffic

    +
    (GcpIpRule)-[DENIED_BY]->(GCPFirewall)
    +
    +
    +
  • +
+
+
+
+

IpRange

+

Representation of an IP range or subnet.

+ ++++ + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

CIDR notation for the IP range. E.g. “0.0.0.0/0” for the whole internet.

+
+

Relationships

+
    +
  • GCP Firewall rules are defined on IpRange objects.

    +
    (GCPIpRule, IpRule, IpPermissionInbound)<-[MEMBER_OF_IP_RULE)-(:IpRange)
    +
    +
    +
  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/github/config.html b/modules/github/config.html new file mode 100644 index 0000000000..543097b3de --- /dev/null +++ b/modules/github/config.html @@ -0,0 +1,613 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Github Configuration — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Github Configuration

+

Follow these steps to analyze GitHub repos and other objects with Cartography.

+
    +
  1. Prepare your GitHub credentials.

    +
      +
    1. Prepare a GitHub token; the following scopes are required, at minimum: repo, read:org, read:user, user:email

    2. +
    3. GitHub ingest supports multiple endpoints, such as a public instance and an enterprise instance by taking a base64-encoded config object structured as +.. code-block:: json

      +
      +
      +
      {
      +
      “organization”: [
      +
      {

      “token”: “faketoken”, +“url”: “https://api.github.com/graphql”, +“name”: “fakeorg”

      +
      +
      +

      }, +{

      +
      +

      “token”: “stillfake”, +“url”: “https://github.example.com/api/graphql”, +“name”: “fakeorg”

      +
      +

      }]

      +
      +
      +
      +
      +

      }

      +
      +
    4. +
    5. For each GitHub instance you want to ingest, generate an API token as documented in the API reference

    6. +
    7. Create your auth config as shown above using the token obtained in the previous step. If you are configuring only the public GitHub instance, you can just use the first config block and delete the second. The name field is for the organization name you want to ingest.

    8. +
    9. Base64 encode the auth object. You can encode the above sample in Python using +.. code-block:: python

      +
      +

      import json +import base64 +auth_json = json.dumps({“organization”:[{“token”:”faketoken”,”url”:”https://api.github.com/graphql”,”name”:”fakeorg”},{“token”:”stillfake”,”url”:”https://github.example.com/api/graphql”,”name”:”fakeorg”}]}) +base64.b64encode(auth_json.encode())

      +
      +

      and the resulting environment variable would be eyJvcmdhbml6YXRpb24iOiBbeyJ0b2tlbiI6ICJmYWtldG9rZW4iLCAidXJsIjogImh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vZ3JhcGhxbCIsICJuYW1lIjogImZha2VvcmcifSwgeyJ0b2tlbiI6ICJzdGlsbGZha2UiLCAidXJsIjogImh0dHBzOi8vZ2l0aHViLmV4YW1wbGUuY29tL2FwaS9ncmFwaHFsIiwgIm5hbWUiOiAiZmFrZW9yZyJ9XX0=

      +
    10. +
    +
  2. +
  3. Populate an environment variable of your choice with the contents of the base64 output from the previous step.

  4. +
  5. Call the cartography CLI with --github-config-env-var YOUR_ENV_VAR_HERE.

  6. +
  7. cartography will then load your graph with data from all the organizations you specified.

  8. +
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/github/index.html b/modules/github/index.html new file mode 100644 index 0000000000..ac22bc4dc9 --- /dev/null +++ b/modules/github/index.html @@ -0,0 +1,571 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Github — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Github

+

The github module has the following coverage:

+
    +
  • Repos

  • +
  • Branches

  • +
  • Users

  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/github/schema.html b/modules/github/schema.html new file mode 100644 index 0000000000..d3b907e8df --- /dev/null +++ b/modules/github/schema.html @@ -0,0 +1,1037 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Github Schema — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+ + +
+
+ +
+

Github Schema

+
+

GitHubRepository

+

Representation of a single GitHubRepository (repo) repository object. This node contains all data unique to the repo.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first created this node

lastupdated

Timestamp of the last time the node was updated

id

The GitHub repo id. These are not unique across GitHub instances, so are prepended with the API URL the id applies to

createdat

GitHub timestamp from when the repo was created

name

Name of the repo

fullname

Name of the organization and repo together

description

Text describing the repo

primarylanguage

The primary language used in the repo

homepage

The website used as a homepage for project information

defaultbranch

The default branch used by the repo, typically master

defaultbranchid

The unique identifier of the default branch

private

True if repo is private

disabled

True if repo is disabled

archived

True if repo is archived

locked

True if repo is locked

giturl

URL used to access the repo from git commandline

url

Web URL for viewing the repo

sshurl

URL for access the repo via SSH

updatedat

GitHub timestamp for last time repo was modified

+
+

Relationships

+
    +
  • GitHubUsers or GitHubOrganizations own GitHubRepositories.

    +
    (GitHubUser)-[OWNER]->(GitHubRepository)
    +(GitHubOrganization)-[OWNER]->(GitHubRepository)
    +
    +
    +
  • +
  • GitHubRepositories in an organization can have outside collaborators with different permissions, including ADMIN, +WRITE, MAINTAIN, TRIAGE, and READ (Reference).

    +
    (GitHubUser)-[:OUTSIDE_COLLAB_{ACTION}]->(GitHubRepository)
    +
    +
    +
  • +
  • GitHubRepositories use ProgrammingLanguages

    +
    (GitHubRepository)-[:LANGUAGE]->(ProgrammingLanguage)
    +
    +
    +
  • +
  • GitHubRepositories have GitHubBranches

    +
    (GitHubRepository)-[:BRANCH]->(GitHubBranch)
    +
    +
    +
  • +
  • GitHubTeams can have various levels of access to GitHubRepositories.

    +
    (GitHubTeam)-[ADMIN|READ|WRITE|TRIAGE|MAINTAIN]->(GitHubRepository)
    +
    +
    +
  • +
+
+
+
+

GitHubOrganization

+

Representation of a single GitHubOrganization organization object. This node contains minimal data for the GitHub Organization.

+ ++++ + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first created this node

lastupdated

Timestamp of the last time the node was updated

id

The URL of the GitHub organization

username

Name of the organization

+
+

Relationships

+
    +
  • GitHubOrganizations own GitHubRepositories.

    +
    (GitHubOrganization)-[OWNER]->(GitHubRepository)
    +
    +
    +
  • +
  • GitHubTeams are resources under GitHubOrganizations

    +
    (GitHubOrganization)-[RESOURCE]->(GitHubTeam)
    +
    +
    +
  • +
+
+
+
+

GitHubTeam

+

A GitHubTeam organization object.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first created this node

lastupdated

Timestamp of the last time the node was updated

id

The URL of the GitHub Team

name

The name (a.k.a URL slug) of the GitHub Team

description

Description of the GitHub team

+
+

Relationships

+
    +
  • GitHubTeams can have various levels of access to GitHubRepositories.

    +
    (GitHubTeam)-[ADMIN|READ|WRITE|TRIAGE|MAINTAIN]->(GitHubRepository)
    +
    +
    +
  • +
  • GitHubTeams are resources under GitHubOrganizations

    +
    (GitHubOrganization)-[RESOURCE]->(GitHubTeam)
    +
    +
    +
  • +
+
+
+
+

GitHubUser

+

Representation of a single GitHubUser user object. This node contains minimal data for the GitHub User.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first created this node

lastupdated

Timestamp of the last time the node was updated

id

The URL of the GitHub user

username

Name of the user

fullname

The full name

has_2fa_enabled

Whether the user has 2-factor authentication enabled

role

Either ‘ADMIN’ (denoting that the user is an owner of a Github organization) or ‘MEMBER’

is_site_admin

Whether the user is a site admin

permission

Only present if the user is an outside collaborator of this repo.

+

permission is either ADMIN, MAINTAIN, READ, TRIAGE, or WRITE (ref). +| email | The user’s publicly visible profile email. +| company | The user’s public profile company.

+
+

Relationships

+
    +
  • GitHubUsers own GitHubRepositories.

    +
    (GitHubUser)-[OWNER]->(GitHubRepository)
    +
    +
    +
  • +
  • GitHubRepositories in an organization can have outside collaborators with different permissions, including ADMIN, +WRITE, MAINTAIN, TRIAGE, and READ (Reference).

    +
    (GitHubUser)-[:OUTSIDE_COLLAB_{ACTION}]->(GitHubRepository)
    +
    +
    +
  • +
+
+
+
+

GitHubBranch

+

Representation of a single GitHubBranch ref object. This node contains minimal data for a repository branch.

+ ++++ + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first created this node

lastupdated

Timestamp of the last time the node was updated

id

The GitHub branch id. These are not unique across GitHub instances, so are prepended with the API URL the id applies to

name

Name of the branch

+
+

Relationships

+
    +
  • GitHubRepositories have GitHubBranches.

    +
    (GitHubBranch)<-[BRANCH]-(GitHubRepository)
    +
    +
    +
  • +
+
+
+
+

ProgrammingLanguage

+

Representation of a single Programming Language language object. This node contains programming language information.

+ ++++ + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first created this node

lastupdated

Timestamp of the last time the node was updated

id

Language ids need not be tracked across instances, so defaults to the name

name

Name of the language

+
+

Relationships

+
    +
  • GitHubRepositories use ProgrammingLanguages.

    +
    (ProgrammingLanguage)<-[LANGUAGE]-(GitHubRepository)
    +
    +
    +
  • +
+
+
+
+

Dependency::PythonLibrary

+

Representation of a Python library as listed in a requirements.txt +or setup.cfg file. +Within a setup.cfg file, cartography will load everything from install_requires, setup_requires, and extras_require.

+ ++++ + + + + + + + + + + + + + + + + +

Field

Description

id

The canonicalized name of the library. If the library was pinned in a requirements file using the == operator, then id has the form {canonical name}|{pinned_version}.

name

The canonicalized name of the library.

version

The exact version of the library. This field is only present if the library was pinned in a requirements file using the == operator.

+
+

Relationships

+
    +
  • Software on Github repos can import Python libraries by optionally specifying a version number.

    +
    (GitHubRepository)-[:REQUIRES{specifier}]->(PythonLibrary)
    +
    +
    +
      +
    • specifier: A string describing this library’s version e.g. “<4.0,>=3.0” or “==1.0.2”. This field is only present on the :REQUIRES edge if the repo’s requirements file provided a version pin.

    • +
    +
  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/gsuite/config.html b/modules/gsuite/config.html new file mode 100644 index 0000000000..148872180c --- /dev/null +++ b/modules/gsuite/config.html @@ -0,0 +1,675 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GSuite Configuration — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

GSuite Configuration

+

This module allows authentication from a service account or via OAuth tokens.

+

Method 1: Using service account (legacy)

+

Ingesting GSuite Users and Groups utilizes the Google Admin SDK.

+
    +
  1. Enable Google API access

  2. +
  3. Create a new G Suite user account and accept the Terms of Service. This account will be used as the domain-wide delegated access.

  4. +
  5. Perform G Suite Domain-Wide Delegation of Authority

  6. +
  7. Download the service account’s credentials

  8. +
  9. Export the environmental variables:

    +
      +
    1. GSUITE_GOOGLE_APPLICATION_CREDENTIALS - location of the credentials file.

    2. +
    3. GSUITE_DELEGATED_ADMIN - email address that you created in step 2

    4. +
    +
  10. +
+
+
+

Method 2: Using OAuth

+
    +
  1. Create an App on Google Cloud Console

  2. +
  3. Refer to follow documentation if needed:

    +
      +
    1. https://developers.google.com/admin-sdk/directory/v1/quickstart/python

    2. +
    3. https://developers.google.com/workspace/guides/get-started

    4. +
    5. https://support.google.com/a/answer/7281227?hl=fr

    6. +
    +
  4. +
  5. Download credentials file

  6. +
  7. Use helper script below for OAuth flow to obtain refresh_token

  8. +
  9. Serialize needed secret +.. code-block:: python

    +
    +

    import json +import base64 +auth_json = json.dumps({“client_id”:”xxxxx.apps.googleusercontent.com”,”client_secret”:”ChangeMe”, “refresh_token”:”ChangeMe”, “token_uri”: “https://oauth2.googleapis.com/token”}) +base64.b64encode(auth_json.encode())

    +
    +
  10. +
  11. Populate an environment variable of your choice with the contents of the base64 output from the previous step.

  12. +
  13. Call the cartography CLI with --gsuite-tokens-env-var YOUR_ENV_VAR_HERE and --gsuite-auth-method oauth.

  14. +
+

Google Oauth Helper :

+
from __future__ import print_function
+import json
+import os
+
+from google_auth_oauthlib.flow import InstalledAppFlow
+from googleapiclient.discovery import build
+
+
+scopes = ["https://www.googleapis.com/auth/admin.directory.userreadonly", "https://www.googleapis.com/auth/admin.directory.group.readonly", "https://www.googleapis.com/auth/admin.directory.group.member"]
+
+print('Go to https://console.cloud.google.com/ > API & Services > Credentials and download secrets')
+project_id = input('Provide your project ID:')
+client_id = input('Provide your client ID:')
+client_secret = input('Provide your client secret:')
+with open('credentials.json', 'w', encoding='utf-8') as fc:
+    data = {
+        "installed": {
+            "client_id": client_id,
+            "project_id": project_id,
+            "auth_uri":"https://accounts.google.com/o/oauth2/auth",
+            "token_uri":"https://oauth2.googleapis.com/token",
+            "auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs",
+            "client_secret":"client_secret",
+            "redirect_uris":["http://localhost"]
+        }}
+    json.dump(data, fc)
+flow = InstalledAppFlow.from_client_secrets_file(
+    'credentials.json', scopes)
+flow.redirect_uri = 'http://localhost'
+auth_url, _ = flow.authorization_url(prompt='consent')
+print(f'Please go to this URL: {auth_url}')
+code = input('Enter the authorization code: ')
+flow.fetch_token(code=code)
+creds = flow.credentials
+print('Testing your credentials by gettings first 10 users in the domain ...')
+service = build('admin', 'directory_v1', credentials=creds)
+print('Getting the first 10 users in the domain')
+results = service.users().list(customer='my_customer', maxResults=10,
+                                orderBy='email').execute()
+users = results.get('users', [])
+if not users:
+    print('No users in the domain.')
+else:
+    print('Users:')
+    for user in users:
+        print(u'{0} ({1})'.format(user['primaryEmail'],
+                                    user['name']['fullName']))
+print('Your credentials:')
+print(json.dumps(creds.to_json(), indent=2))
+os.remove('credentials.json')
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/gsuite/index.html b/modules/gsuite/index.html new file mode 100644 index 0000000000..d907fffbbf --- /dev/null +++ b/modules/gsuite/index.html @@ -0,0 +1,577 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Google GSuite — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Google GSuite

+

The gsuite module has the following coverage:

+
    +
  • Users

  • +
  • Groups

  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/gsuite/schema.html b/modules/gsuite/schema.html new file mode 100644 index 0000000000..1815ccb080 --- /dev/null +++ b/modules/gsuite/schema.html @@ -0,0 +1,751 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GSuite Schema — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

GSuite Schema

+
+

GSuiteUser

+

Reference: +https://developers.google.com/admin-sdk/directory/v1/reference/users#resource

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

id

The unique ID for the user as a string. A user id can be used as a user request URI’s userKey

user_id

duplicate of id.

agreed_to_terms

This property is true if the user has completed an initial login and accepted the Terms of Service agreement.

change_password_at_next_login

Indicates if the user is forced to change their password at next login. This setting doesn’t apply when the user signs in via a third-party identity provider.

creation_time

The time the user’s account was created. The value is in ISO 8601 date and time format. The time is the complete date plus hours, minutes, and seconds in the form YYYY-MM-DDThh:mm:ssTZD. For example, 2010-04-05T17:30:04+01:00.

customer_id

The customer ID to retrieve all account users. You can use the alias my_customer to represent your account’s customerId. As a reseller administrator, you can use the resold customer account’s customerId. To get a customerId, use the account’s primary domain in the domain parameter of a users.list request.

etag

ETag of the resource

include_in_global_address_list

Indicates if the user’s profile is visible in the G Suite global address list when the contact sharing feature is enabled for the domain. For more information about excluding user profiles, see the administration help center.

ip_whitelisted

If true, the user’s IP address is white listed.

is_admin

Indicates a user with super admininistrator privileges. The isAdmin property can only be edited in the Make a user an administrator operation (makeAdmin method). If edited in the user insert or update methods, the edit is ignored by the API service.

is_delegated_admin

Indicates if the user is a delegated administrator. Delegated administrators are supported by the API but cannot create or undelete users, or make users administrators. These requests are ignored by the API service. Roles and privileges for administrators are assigned using the Admin console.

is_enforced_in_2_sv

Is 2-step verification enforced (Read-only)

is_enrolled_in_2_sv

Is enrolled in 2-step verification (Read-only)

is_mailbox_setup

Indicates if the user’s Google mailbox is created. This property is only applicable if the user has been assigned a Gmail license.

kind

The type of the API resource. For Users resources, the value is admin#directory#user.

last_login_time

The last time the user logged into the user’s account. The value is in ISO 8601 date and time format. The time is the complete date plus hours, minutes, and seconds in the form YYYY-MM-DDThh:mm:ssTZD. For example, 2010-04-05T17:30:04+01:00.

name

First name + Last name

family_name

The user’s last name. Required when creating a user account.

given_name

The user’s first name. Required when creating a user account.

org_unit_path

The full path of the parent organization associated with the user. If the parent organization is the top-level, it is represented as a forward slash (/).

primary_email

The user’s primary email address. This property is required in a request to create a user account. The primaryEmail must be unique and cannot be an alias of another user.

suspended

Indicates if user is suspended

thumbnail_photo_etag

ETag of the user’s photo

thumbnail_photo_url

Photo Url of the user

lastupdated

Timestamp of when a sync job last updated this node

firstseen

Timestamp of when a sync job first discovered this node

+
+

Relationships

+
    +
  • GSuiteUser is an identity for a Human

    +
    (Human)-[IDENTITY_GSUITE]->(GSuiteUser)
    +
    +
    +
  • +
+
+
+
+

GSuiteGroup

+

Reference: +https://developers.google.com/admin-sdk/directory/v1/reference/groups

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

id

The unique ID of a group. A group id can be used as a group request URI’s groupKey.

admin_created

Value is true if this group was created by an administrator rather than a user.

description

An extended description to help users determine the purpose of a group. For example, you can include information about who should join the group, the types of messages to send to the group, links to FAQs about the group, or related groups. Maximum length is 4,096 characters.

direct_members_count

The number of users that are direct members of the group. If a group is a member (child) of this group (the parent), members of the child group are not counted in the directMembersCount property of the parent group

email

The group’s email address. If your account has multiple domains, select the appropriate domain for the email address. The email must be unique. This property is required when creating a group. Group email addresses are subject to the same character usage rules as usernames, see the administration help center for the details.

etag

ETag of the resource

kind

The type of the API resource. For Groups resources, the value is admin#directory#group.

name

The group’s display name.

lastupdated

Timestamp of when a sync job last updated this node

firstseen

Timestamp of when a sync job first discovered this node

+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/index.html b/modules/index.html new file mode 100644 index 0000000000..f9c7508376 --- /dev/null +++ b/modules/index.html @@ -0,0 +1,535 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <no title> — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/jamf/index.html b/modules/jamf/index.html new file mode 100644 index 0000000000..edeca58816 --- /dev/null +++ b/modules/jamf/index.html @@ -0,0 +1,567 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Jamf — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/jamf/schema.html b/modules/jamf/schema.html new file mode 100644 index 0000000000..53167abce2 --- /dev/null +++ b/modules/jamf/schema.html @@ -0,0 +1,611 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Jamf Schema — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Jamf Schema

+
+

JamfComputerGroup

+

Representation of a Jamf computer group.

+ ++++ + + + + + + + + + + + + + + + + +

Field

Description

id

The group id

name

The friendly name of the group

is_smart

Whether the group is smart

+
+

Relationships

+
    +
  • Coming soon!

  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/kubernetes/config.html b/modules/kubernetes/config.html new file mode 100644 index 0000000000..8e2a9ed0be --- /dev/null +++ b/modules/kubernetes/config.html @@ -0,0 +1,573 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Kubernetes Configuration — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Kubernetes Configuration

+

Follow these steps to analyze Kubernetes objects in Cartography.

+
    +
  1. Configure a kubeconfig file specifying access to one or mulitple clusters.

    +
      +
    • Access to mutliple K8 clusters can be organized in a single kubeconfig file. Intel module of Kubernetes will automatically detect that and attempt to sync each cluster.

    • +
    +
  2. +
  3. Note down the path of configured kubeconfig file and pass it to cartography CLI with --k8s-kubeconfig parameter.

  4. +
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/kubernetes/index.html b/modules/kubernetes/index.html new file mode 100644 index 0000000000..1103c9508f --- /dev/null +++ b/modules/kubernetes/index.html @@ -0,0 +1,574 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Kubernetes — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Kubernetes

+

The kubernetes module has the following coverage:

+
    +
  • Cluster

  • +
  • Namespace

  • +
  • Secret

  • +
  • Service

  • +
  • Pod

  • +
  • Container

  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/kubernetes/schema.html b/modules/kubernetes/schema.html new file mode 100644 index 0000000000..186eb1bdfa --- /dev/null +++ b/modules/kubernetes/schema.html @@ -0,0 +1,955 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Kubernetes Schema — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+ + +
+
+ +
+

Kubernetes Schema

+
+

KubernetesCluster

+

Representation of a Kubernetes Cluster.

+ ++++ + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Identifier for the cluster i.e. UID of kube-system namespace

name

Name assigned to the cluster which is derived from kubeconfig context

+
+

Relationships

+
    +
  • KubernetesCluster has KubernetesNamespaces.

    +
    (KubernetesCluster)-[HAS_NAMESPACE]->(KubernetesNamespace)
    +
    +
    +
  • +
  • KubernetesCluster can have KubernetesPods.

    +
    (KubernetesCluster)-[HAS_POD]->(KubernetesPod)
    +
    +
    +
  • +
+
+
+
+

KubernetesNamespace

+

Representation of a Kubernetes Namespace.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

UID of the kubernetes namespace

name

Name of the kubernetes namespace

created_at

Timestamp of the creation time of the kubernetes namespace

deleted_at

Timestamp of the deletion time of the kubernetes namespace

+
+

Relationships

+
    +
  • KubernetesNamespace can have KubernetesPods.

    +
    (KubernetesNamespace)-[HAS_POD]->(KubernetesPod)
    +
    +
    +
  • +
  • KubernetesNamespace can have KubernetesServices.

    +
    (KubernetesNamespace)-[HAS_SERVICE]->(KubernetesService)
    +
    +
    +
  • +
  • KubernetesNamespace can have KubernetesSecrets.

    +
    (KubernetesNamespace)-[HAS_SECRET]->(KubernetesSecret)
    +
    +
    +
  • +
+
+
+
+

KubernetesPod

+

Representation of a Kubernetes Pod.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

UID of the kubernetes pod

name

Name of the kubernetes pod

status_phase

The phase of a Pod is a simple, high-level summary of where the Pod is in its lifecycle.

created_at

Timestamp of the creation time of the kubernetes pod

deleted_at

Timestamp of the deletion time of the kubernetes pod

+
+

Relationships

+
    +
  • KubernetesPod has KubernetesContainers.

    +
    (KubernetesPod)-[HAS_CONTAINER]->(KubernetesContainer)
    +
    +
    +
  • +
+
+
+
+

KubernetesContainer

+

Representation of a Kubernetes Container.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Identifier for the container which is derived from the UID of pod and the name of container

name

Name of the container in kubernetes pod

image

Docker image used in the container

status_image_id

ImageID of the container’s image.

status_image_sha

The SHA portion of the status_image_id

status_ready

Specifies whether the container has passed its readiness probe.

status_started

Specifies whether the container has passed its startup probe.

statys_state

State of the container (running, terminated, waiting)

+
+

Relationships

+
    +
  • KubernetesPod has KubernetesContainers.

    +
    (KubernetesPod)-[HAS_CONTAINER]->(KubernetesContainer)
    +
    +
    +
  • +
+
+
+
+

KubernetesService

+

Representation of a Kubernetes Service.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

UID of the kubernetes service

name

Name of the kubernetes service

created_at

Timestamp of the creation time of the kubernetes service

deleted_at

Timestamp of the deletion time of the kubernetes service

type

Type of kubernetes service e.g. ClusterIP

load_balancer_ip

IP of the load balancer when service type is LoadBalancer

ingress_host

Hostname of the ingress endpoint, if any

ingress_ip

IP of the ingress endpoint, if any

+
+

Relationships

+
    +
  • KubernetesService can serve KubernetesPods.

    +
    (KubernetesService)-[SERVES_POD]->(KubernetesPod)
    +
    +
    +
  • +
+
+
+
+

KubernetesSecret

+

Representation of a Kubernetes Secret.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

UID of the kubernetes secret

name

Name of the kubernetes secret

created_at

Timestamp of the creation time of the kubernetes secret

deleted_at

Timestamp of the deletion time of the kubernetes secret

type

Type of kubernetes secret e.g. Opaque

+
+

Relationships

+
    +
  • KubernetesNamespace can have KubernetesSecrets.

    +
    (KubernetesNamespace)-[HAS_SECRET]->(KubernetesSecret)
    +
    +
    +
  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/lastpass/config.html b/modules/lastpass/config.html new file mode 100644 index 0000000000..0379cb160a --- /dev/null +++ b/modules/lastpass/config.html @@ -0,0 +1,573 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Lastpass Configuration — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Lastpass Configuration

+

Follow these steps to analyze Lastpass objects with Cartography.

+
    +
  1. Prepare your Lastpass CID & ProvHash key.

    +
      +
    1. Get your CID (account number) and ProvHash from Lastpass Where can I find the CID and API secret?

    2. +
    3. Populate an environment variable with the CID and Provhash. You can pass the environment variable name via CLI with the --lastpass-cid-env-var and --lastpass-provhash-env-var parameter.

    4. +
    +
  2. +
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/lastpass/index.html b/modules/lastpass/index.html new file mode 100644 index 0000000000..5206832c65 --- /dev/null +++ b/modules/lastpass/index.html @@ -0,0 +1,569 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Lastpass — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Lastpass

+

The lastpass module has the following coverage:

+
    +
  • Users

  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/lastpass/schema.html b/modules/lastpass/schema.html new file mode 100644 index 0000000000..fbf415c94c --- /dev/null +++ b/modules/lastpass/schema.html @@ -0,0 +1,682 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Lastpass Schema — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Lastpass Schema

+
+

Human

+

Lastpass use Human node as pivot with other Identity Providers (GSuite, GitHub …)

+

Human nodes are not created by Lastpass module, link is made using analysis job.

+
+

Relationships

+
    +
  • Human as an access to Lastpass

    +
    (Human)-[IDENTITY_LASTPASS]->(LastpassUser)
    +
    +
    +
  • +
+
+
+
+

LastpassUser

+

Representation of a single User in Lastpass

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first created this node

lastupdated

Timestamp of the last time the node was updated

id

Lastpass ID

name

Full name of the user

email

User email

created

Timestamp of when the account was created

last_pw_change

Timestamp of the last master password change

last_login

Timestamp of the last login

neverloggedin

Flag indicating the user never logged in

disabled

Flag indicating accout is disabled

admin

Flag for admin account

totalscore

Lastpass security score (max 100)

mpstrength

Master password strenght (max 100)

sites

Number of site credentials stored

notes

Number of secured notes stored

formfills

Number of forms stored

applications

Number of applications (mobile) stored

attachments

Number of file attachments stored

password_reset_required

Flag indicating user requested password reset

multifactor

MFA method (null if None)

+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/okta/config.html b/modules/okta/config.html new file mode 100644 index 0000000000..3f75c0ad0b --- /dev/null +++ b/modules/okta/config.html @@ -0,0 +1,579 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Okta Configuration — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Okta Configuration

+

Follow these steps to analyze Okta objects with Cartography.

+
    +
  1. Prepare your Okta API token.

    +
      +
    1. Generate your API token by following the steps from the Okta Create An API Token documentation

    2. +
    3. Populate an environment variable with the API token. You can pass the environment variable name via CLI with the --okta-api-key-env-var parameter.

    4. +
    5. Use the CLI --okta-org-id parameter with the organization ID that you wish to query. The organization ID is the first part of the Okta URL for your organization.

    6. +
    7. If you are using Okta to administer AWS as a SAML provider then the module will automatically match OktaGroups to the AWSRole they control access for.

      +
        +
      • If you are using a regex other than the standard okta group to role regex ^aws\#\S+\#(?{{role}}[\w\-]+)\#(?{{accountid}}\d+)$ defined in Step 5: Enabling Group Based Role Mapping in Okta then you can specify your regex with the --okta-saml-role-regex parameter.

      • +
      +
    8. +
    +
  2. +
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/okta/index.html b/modules/okta/index.html new file mode 100644 index 0000000000..9ae61e45a5 --- /dev/null +++ b/modules/okta/index.html @@ -0,0 +1,576 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Okta — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Okta

+

The okta module has the following coverage:

+
    +
  • Users

  • +
  • Groups

  • +
  • Organizations

  • +
  • Roles

  • +
  • Applications

  • +
  • Factors

  • +
  • Trusted Origins

  • +
  • Reply URIs

  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/okta/schema.html b/modules/okta/schema.html new file mode 100644 index 0000000000..8b964b9eec --- /dev/null +++ b/modules/okta/schema.html @@ -0,0 +1,1180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Okta Schema — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+ +
+
+ +
+
+ +
+

Okta Schema

+
+

OktaOrganization

+

Representation of an Okta Organization.

+ ++++ + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The name of the Okta Organization, e.g. “lyft”

name

The name of the Okta Organization, e.g. “lyft”

+
+

Relationships

+
    +
  • An OktaOrganization contains OktaUsers

    +
    (OktaOrganization)-[RESOURCE]->(OktaUser)
    +
    +
    +
  • +
  • An OktaOrganization contains OktaGroups.

    +
    (OktaOrganization)-[RESOURCE]->(OktaGroup)
    +
    +
    +
  • +
  • An OktaOrganization contains OktaApplications

    +
    (OktaOrganization)-[RESOURCE]->(OktaApplication)
    +
    +
    +
  • +
  • An OktaOrganization has OktaTrustedOrigins

    +
    (OktaOrganization)-[RESOURCE]->(OktaTrustedOrigin)
    +
    +
    +
  • +
  • An OktaOrganization has OktaAdministrationRoles

    +
    (OktaOrganization)-[RESOURCE]->(OktaAdministrationRole)
    +
    +
    +
  • +
+
+
+
+

OktaUser

+

Representation of an Okta User.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

id

user id

first_name

user first name

last_name

user last name

login

user usernmae used to login (usually email)

email

user email

second_email

user secondary email

mobile_phone

user mobile phone

created

date and time of creation

activated

date and time of activation

status_changed

date and time of the last state change

last_login

date and time of last login

okta_last_updated

date and time of last user property changes

password_changed

date and time of last password change

transition_to_status

date and time of last state transition change

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

+
+

Relationships

+
    +
  • An OktaOrganization contains OktaUsers

    +
    (OktaUser)<-[RESOURCE]->(OktaOrganization)
    +
    +
    +
  • +
  • OktaUsers are assigned OktaApplication

    +
    (OktaUser)-[APPLICATION]->(OktaApplication)
    +
    +
    +
  • +
  • OktaUser is an identity for a Human

    +
    (OktaUser)<-[IDENTITY_OKTA]-(Human)
    +
    +
    +
  • +
  • An OktaUser can be a member of an OktaGroup

    +
    (OktaUser)-[MEMBER_OF_OKTA_GROUP]->(OktaGroup)
    +
    +
    +
  • +
  • An OktaUser can be a member of an OktaAdministrationRole

    +
    (OktaUser)-[MEMBER_OF_OKTA_ROLE]->(OktaAdministrationRole)
    +
    +
    +
  • +
  • OktaUsers can have authentication factors

    +
    (OktaUser)-[FACTOR]->(OktaUserFactor)
    +
    +
    +
  • +
+
+
+
+

OktaGroup

+

Representation of an Okta Group.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

id

application id

name

group name

description

group description

sam_account_name

windows SAM account name mapped

dn

group dn

windows_domain_qualified_name

windows domain name

external_id

group foreign id

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

+
+

Relationships

+
    +
  • OktaOrganizations contain OktaGroups

    +
    (OktaGroup)<-[RESOURCE]->(OktaOrganizations)
    +
    +
    +
  • +
  • OktaApplications can be assigned to OktaGroups

    +
    (OktaGroup)-[APPLICATION]->(OktaApplication)
    +
    +
    +
  • +
  • An OktaUser can be a member of an OktaGroup

    +
    (OktaUser)-[MEMBER_OF_OKTA_GROUP]->(OktaGroup)
    +
    +
    +
  • +
  • An OktaGroup can be a member of an OktaAdministrationRole

    +
    (OktaGroup)-[MEMBER_OF_OKTA_ROLE]->(OktaAdministrationRole)
    +
    +
    +
  • +
+
+
+
+

OktaApplication

+

Representation of an Okta Application.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

id

application id

name

application name

label

application label

created

application creation date

okta_last_updated

date and time of last application property changes

status

application status

activated

application activation state

features

application features

sign_on_mode

application signon mode

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

+
+

Relationships

+
    +
  • OktaApplication is a resource of an OktaOrganization

    +
    (OktaApplication)<-[RESOURCE]->(OktaOrganization)
    +
    +
    +
      +
    • OktaGroups can be assigned OktaApplications

    • +
    +
    (OktaGroup)-[APPLICATION]->(OktaApplication)
    +
    +
    +
      +
    • OktaUsers are assigned OktaApplications

    • +
    +
    (OktaUser)-[APPLICATION]->(OktaApplication)
    +
    +
    +
      +
    • OktaApplications have ReplyUris

    • +
    +
    (ReplyUri)-[REPLYURI]->(OktaApplication)
    +
    +
    +
  • +
+
+
+
+

OktaUserFactor

+

Representation of Okta User authentication Factors.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

id

factor id

factor_type

factor type

provider

factor provider

status

factor status

created

factor creation date and time

okta_last_updated

date and time of last property changes

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

+
+

Relationships

+
    +
  • OktaUsers can have authentication Factors

    +
    (OktaUser)-[FACTOR]->(OktaUserFactor)
    +
    +
    +
  • +
+
+
+
+

OktaTrustedOrigin

+

Representation of an Okta Trusted Origin for login/logout or recovery operations.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

id

trusted origin id

name

name

scopes

array of scope

status

status

created

date & time of creation in okta

create_by

id of user who created the trusted origin

okta_last_updated

date and time of last property changes

okta_last_updated_by

id of user who last updated the trusted origin

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

+
+

Relationships

+
    +
  • An OktaOrganization has OktaTrustedOrigins.

    +
    (OktaOrganization)-[RESOURCE]->(OktaTrustedOrigin)
    +
    +
    +
  • +
+
+
+
+

OktaAdministrationRole

+

Representation of an Okta Administration Role.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

id

role id mapped to the type

type

role type

label

role label

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

+
+

Relationships

+
    +
  • OktaUsers can be members of OktaAdministrationRoles

    +
    (OktaUser)-[MEMBER_OF_OKTA_ROLE]->(OktaAdministrationRole)
    +
    +
    +
  • +
  • An OktaGroup can be a member of an OktaAdministrationRolee

    +
    (OktaGroup)-[MEMBER_OF_OKTA_ROLE]->(OktaAdministrationRole)
    +
    +
    +
      +
    • An OktaOrganization contains OktaAdministrationRoles

      +
      (OktaOrganization)-[RESOURCE]->(OktaAdministrationRole)
      +
      +
      +
    • +
    +
  • +
+
+
+
+

Reply Uri

+

Representation of Okta Application ReplyUri.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

id

uri the app can send the reply to

uri

uri the app can send the reply to

valid

is the DNS of the reply uri valid. Invalid replyuris can lead to oath phishing

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

+
+

Relationships

+
    +
  • OktaApplications have ReplyUris

    +
    (ReplyUri)-[REPLYURI]->(OktaApplication)
    +
    +
    +
  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/pagerduty/config.html b/modules/pagerduty/config.html new file mode 100644 index 0000000000..fd68e7b148 --- /dev/null +++ b/modules/pagerduty/config.html @@ -0,0 +1,574 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Pagerduty Configuration — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Pagerduty Configuration

+

Follow these steps to analyze PagerDuty objects with Cartography.

+
    +
  1. Prepare your PagerDuty API key.

    +
      +
    1. Generate your API token by following the steps from the PagerDuty Generating API Keys documentation

    2. +
    3. Populate an environment variable with the API key. You can pass the environment variable name via CLI with the --pagerduty-api-key-env-var parameter.

    4. +
    5. You can set the timeout for pagerduty requests via the CLI with --pagerduty-request-timeout parameter.

    6. +
    +
  2. +
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/pagerduty/index.html b/modules/pagerduty/index.html new file mode 100644 index 0000000000..d8fb7103dd --- /dev/null +++ b/modules/pagerduty/index.html @@ -0,0 +1,575 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PagerDuty — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

PagerDuty

+

The pagerduty module has the following coverage:

+
    +
  • Users

  • +
  • Teams

  • +
  • Services

  • +
  • Schedules

  • +
  • Escalation Policies

  • +
  • Integrations

  • +
  • Vendors

  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/pagerduty/schema.html b/modules/pagerduty/schema.html new file mode 100644 index 0000000000..cd65ba1a24 --- /dev/null +++ b/modules/pagerduty/schema.html @@ -0,0 +1,1117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Pagerduty Schema — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+ + +
+
+ +
+

Pagerduty Schema

+
+

PagerDutyEscalationPolicy

+

Representation of a PagerDuty Escalation Policy

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the escalation policy

html_url

the API show URL at which the object is accessible

type

The type of this pagerduty object (escalation_policy)

summary

A short-form, server-generated string that provides succinct, important information about an object suitable for primary labeling of an entity in a client. In many cases, this will be identical to name, though it is not intended to be an identifier.

on_call_handoff_notifications

Determines how on call handoff notifications will be sent for users on the escalation policy. Defaults to “if_has_services”.

name

The name of the escalation policy.

num_loops

The number of times the escalation policy will repeat after reaching the end of its escalation.

+
+

Relationships

+
    +
  • A PagerDutyEscalationPolicy has PagerDutyEscalationPolicyRules

    +
    (PagerDutyEscalationPolicy)-[HAS\_RULE]->(PagerDutyEscalationPolicyRule)
    +
    +
    +
  • +
  • A PagerDutyEscalationPolicy is associated with PagerDutyUsers

    +
    (PagerDutyEscalationPolicy)-[ASSOCIATED\_WITH]->(PagerDutyUser)
    +
    +
    +
  • +
  • A PagerDutyEscalationPolicy is associated with PagerDutySchedules

    +
    (PagerDutyEscalationPolicy)-[ASSOCIATED\_WITH]->(PagerDutySchedule)
    +
    +
    +
  • +
  • A PagerDutyEscalationPolicy is associated with PagerDutyServices

    +
    (PagerDutyEscalationPolicy)-[ASSOCIATED\_WITH]->(PagerDutyService)
    +
    +
    +
  • +
  • A PagerDutyEscalationPolicy is associated with PagerDutyTeams

    +
    (PagerDutyEscalationPolicy)-[ASSOCIATED\_WITH]->(PagerDutyTeam)
    +
    +
    +
  • +
+
+
+
+

PagerDutySchedule

+

Representation of a PagerDuty Schedule

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the schedule

html_url

the API show URL at which the object is accessible

type

The type of this pagerduty object (schedule)

summary

A short-form, server-generated string that provides succinct, important information about an object suitable for primary labeling of an entity in a client. In many cases, this will be identical to name, though it is not intended to be an identifier.

name

The name of the schedule.

time_zone

The time zone of the schedule

description

The description of the schedule

+
+

Relationships

+
    +
  • A PagerDutySchedule has PagerDutyScheduleLayers

    +
    (PagerDutySchedule)-[HAS\_LAYER]->(PagerDutyScheduleLayer)
    +
    +
    +
  • +
+
+
+
+

PagerDutyScheduleLayer

+

Representation of a layer in a PagerDuty Schedule

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the schedule layer

schedule_id

The ID of the schedule this layer is attached to.

start

The start time of this layer

end

The end time of this layer. If null, the layer does not end.

rotation_virtual_start

The effective start time of the layer. This can be before the start time of the schedule.

rotation_turn_length_seconds

The duration of each on-call shift in seconds.

+
+

Relationships

+

No relationships originating from PagerDutyScheduleLayer

+
+
+
+

PagerDutyService

+

Representation of a PagerDuty Service

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the service

html_url

the API show URL at which the object is accessible

type

The type of this pagerduty object (service)

summary

A short-form, server-generated string that provides succinct, important information about an object suitable for primary labeling of an entity in a client. In many cases, this will be identical to name, though it is not intended to be an identifier.

name

The name of this service

description

The user-provided description of the service.

auto_resolve_timeout

Time in seconds that an incident is automatically resolved if left open for that long. Value is null if the feature is disabled. Value must not be negative. Setting this field to 0, null (or unset in POST request) will disable the feature.

acknowledgement_timeout

Time in seconds that an incident changes to the Triggered State after being Acknowledged. Value is null if the feature is disabled. Value must not be negative. Setting this field to 0, null (or unset in POST request) will disable the feature.

created_at

The date/time when this service was created

status

The current state of the Service.

alert_creation

Whether a service creates only incidents, or both alerts and incidents. A service must create alerts in order to enable incident merging.

alert_grouping_parameters_type

The type of Alert Grouping.

incident_urgency_rule_type

The type of incident urgency: whether it’s constant, or it’s dependent on the support hours.

incident_urgency_rule_during_support_hours_type

The type of incident urgency: whether it’s constant, or it’s dependent on the support hours.

incident_urgency_rule_during_support_hours_urgency

The incidents’ urgency, if type is constant.

incident_urgency_rule_outside_support_hours_type

The type of incident urgency: whether it’s constant, or it’s dependent on the support hours.

incident_urgency_rule_outside_support_hours_urgency

The incidents’ urgency, if type is constant.

support_hours_type

The type of support hours

support_hours_time_zone

The time zone for the support hours

support_hours_start_time

The support hours’ starting time of day (date portion is ignored)

support_hours_end_time

support_hours_end_time

support_hours_days_of_week

(no description)

+
+

Relationships

+
    +
  • A PagerDutyService has PagerDutyIntegrations

    +
    (PagerDutyService)-[HAS\_INTEGRATION]->(PagerDutyIntegration)
    +
    +
    +
  • +
+
+
+
+

PagerDutyIntegration

+

Representation of a PagerDuty Integration

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the integration

html_url

the API show URL at which the object is accessible

type

The type of this pagerduty object (integration)

summary

A short-form, server-generated string that provides succinct, important information about an object suitable for primary labeling of an entity in a client. In many cases, this will be identical to name, though it is not intended to be an identifier.

name

The name of this integration

created_at

The date/time when this integration was created.

+
+

Relationships

+
    +
  • A PagerDutyIntegration has PagerDutyVendors

    +
    (PagerDutyIntegration)-[HAS\_VENDOR]->(PagerDutyVendor)
    +
    +
    +
  • +
+
+
+
+

PagerDutyTeam

+

Representation of a PagerDuty Team

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the team

html_url

the API show URL at which the object is accessible

type

The type of this pagerduty object (team)

summary

A short-form, server-generated string that provides succinct, important information about an object suitable for primary labeling of an entity in a client. In many cases, this will be identical to name, though it is not intended to be an identifier.

name

The name of the team

description

The description of the team

default_role

(no description, but returned by API)

+
+

Relationships

+
    +
  • A PagerDutyTeam is associated with PagerDutyServices

    +
    (PagerDutyTeam)-[ASSOCIATED\_WITH]->(PagerDutyServices)
    +
    +
    +
  • +
+
+
+
+

PagerDutyUser

+

Representation of a PagerDuty User

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the user

html_url

the API show URL at which the object is accessible

type

The type of this pagerduty object (user)

summary

A short-form, server-generated string that provides succinct, important information about an object suitable for primary labeling of an entity in a client. In many cases, this will be identical to name, though it is not intended to be an identifier.

name

The name of the user

email

The user’s email address

time_zone

The preferred time zone name. If null, the account’s time zone will be used.

color

The schedule color

role

The user role. Account must have the read_only_users ability to set a user as a read_only_user or a read_only_limited_user, and must have advanced permissions abilities to set a user as observer or restricted_access.

avatar_url

The URL of the user’s avatar.

description

The user’s bio.

invitation_sent

If true, the user has an outstanding invitation.

job_title

The user’s title

+
+

Relationships

+
    +
  • A PagerDutyUser is a member of PagerDutySchedules

    +
    (PagerDutyUser)-[MEMBER\_OF]->(PagerDutySchedule)
    +
    +
    +
  • +
  • A PagerDutyUser is a member of PagerDutyScheduleLayers

    +
    (PagerDutyUser)-[MEMBER\_OF]->(PagerDutyScheduleLayer)
    +
    +
    +
  • +
  • A PagerDutyUser is a member of PagerDutyTeams

    +
    (PagerDutyUser)-[MEMBER\_OF]->(PagerDutyTeam)
    +
    +
    +
  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/semgrep/config.html b/modules/semgrep/config.html new file mode 100644 index 0000000000..a7131041c1 --- /dev/null +++ b/modules/semgrep/config.html @@ -0,0 +1,570 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Semgrep Configuration — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Semgrep Configuration

+

Follow these steps to ingest Semgrep findings with Cartography.

+
    +
  1. Create a token with Agent (CI) and Web API scopes Creating a SEMGREP_APP_TOKEN.

  2. +
  3. Populate an environment variable with the secrets value of the token

  4. +
  5. Pass the environment variable name to the --semgrep-app-token-env-var CLI arg.

  6. +
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/semgrep/index.html b/modules/semgrep/index.html new file mode 100644 index 0000000000..4af9a1a393 --- /dev/null +++ b/modules/semgrep/index.html @@ -0,0 +1,570 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Semgrep — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Semgrep

+

The Semgrep module has the following coverage:

+
    +
  • Deployment

  • +
  • SCA Findings

  • +
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/modules/semgrep/schema.html b/modules/semgrep/schema.html new file mode 100644 index 0000000000..d8de95af4e --- /dev/null +++ b/modules/semgrep/schema.html @@ -0,0 +1,788 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Semgrep Schema — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Semgrep Schema

+
+

SemgrepDeployment

+

Represents a Semgrep Deployment, a unit encapsulating a security organization inside Semgrep Cloud. Works as the parent of all other Semgrep resources.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Unique integer id representing the deployment

slug

Lowercase string id representing the deployment to query the API

name

Name of security organization connected to the deployment

+
+

Relationships

+
    +
  • A SemgrepDeployment contains SemgrepSCAFinding’s

    +
    (SemgrepDeployment)-[RESOURCE]->(SemgrepSCAFinding)
    +
    +
    +
  • +
  • A SemgrepDeployment contains SemgrepSCALocation’s

  • +
+
```
+(SemgrepDeployment)-[RESOURCE]->(SemgrepSCALocation)
+```
+
+```
+
+
+
+
+
+

SemgrepSCAFinding

+

Represents a Semgre Supply Chain finding. This is, a vulnerability in a dependency of a project discovered by Semgrep performing software composition analysis (SCA) and code reachability analysis. Before ingesting this node, make sure you have run Semgrep CI and that it’s connected to Semgrep Cloud Platform Running Semgrep CI with Semgrep Cloud Platform.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

A composed id based using the repository path and the rule that triggered the finding

rule_id

The rule that triggered the finding

repository

The repository path where the finding was discovered

summary

A short title summarizing of the finding

description

Description of the vulnerability.

package_manager

The ecosystem of the dependency where the finding was discovered (e.g. pypi, npm, maven)

severity

Severity of the finding (e.g. CRITICAL, HIGH, MEDIUM, LOW)

cve_id

CVE id of the vulnerability from NVD. Check cve_schema

reachability_check

Whether the vulnerability reachability is confirmed, not confirmed or needs to be manually confirmed

reachability_condition

Description of the reachability condition (e.g. reachable if code is used in X way)

reachability

Whether the vulnerability is reachable or not

transitivity

Whether the vulnerability is transitive or not (e.g. dependency, transitive)

dependency

Dependency where the finding was discovered. Includes dependency name and version

dependency_fix

Dependency version that fixes the vulnerability

ref_urls

List of reference urls for the finding

dependency_file

Path of the file where the finding was discovered (e.g. lock.json, requirements.txt)

dependency_file_url

URL of the file where the finding was discovered

scan_time

Date and time when the finding was discovered in UTC

+
+

Relationships

+
    +
  • An SemgrepSCAFinding connected to a GithubRepository (optional)

    +
    (SemgrepSCAFinding)-[FOUND_IN]->(GithubRepository)
    +
    +
    +
  • +
  • A SemgrepSCAFinding vulnerable dependency usage at SemgrepSCALocation (optional)

    +
    (SemgrepSCAFinding)-[USAGE_AT]->(SemgrepSCALocation)
    +
    +
    +
  • +
+
+
+
+

SemgrepSCALocation

+

Represents the location in a repository where a vulnerable dependency is used in a way that can trigger the vulnerability.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Unique id identifying the location of the finding

path

Path of the file where the usage was discovered

start_line

Line where the usage starts

start_col

Column where the usage starts

end_line

Line where the usage ends

end_col

Column where the usage ends

url

URL of the file where the usage was discovered

+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/objects.inv b/objects.inv new file mode 100644 index 0000000000..d661d8cb6d Binary files /dev/null and b/objects.inv differ diff --git a/ops.html b/ops.html new file mode 100644 index 0000000000..6175539c03 --- /dev/null +++ b/ops.html @@ -0,0 +1,660 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cartography operations guide — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+ + +
+
+ +
+

Cartography operations guide

+

This document contains tips for running Cartography in production.

+
+

Maintaining a up-to-date picture of your infrastructure

+

Running cartography ensures that your Neo4j instance contains the most recent snapshot of your infrastructure. Here’s +how that process works.

+
+

Update tags

+

Each sync run has an update_tag associated with it, +which is the Unix timestamp of when the sync started. +See our docs for more details.

+
+
+

Cleanup jobs

+

Each node and relationship created or updated during the sync will have their lastupdated field set to the +update_tag. At the end of a sync run, nodes and relationships with out-of-date lastupdated fields are considered +stale and will be deleted via a cleanup job.

+
+
+

Sync frequency

+

To keep data updated, you can run cartography as part of a periodic script (cronjobs in Linux, scheduled tasks in +Windows). Determine your needs for data freshness and adjust accordingly.

+
+
+
+

Observability

+
+

statsd

+

Cartography can be configured to send metrics to a statsd server. Specify the +--statsd-enabled flag when running cartography for sync execution times to be recorded and sent to +127.0.0.1:8125 by default (these options are also configurable with the --statsd-host and --statsd-port options). +You can also provide your own --statsd-prefix to make these metrics easier to find in your own environment.

+
+
+
+

Docker image

+

A production-ready docker image is available in GitHub Container Registry. We recommend that you avoid using the :latest tag and instead +use the tag or digest associated with your desired release version, e.g.

+
docker pull ghcr.io/lyft/cartography:0.61.0
+
+
+

This image can then be ran with any of your desired command line flags:

+
docker run --rm ghcr.io/lyft/cartography:0.61.0 --help
+
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/search.html b/search.html new file mode 100644 index 0000000000..3f856197f5 --- /dev/null +++ b/search.html @@ -0,0 +1,522 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Search — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +

Search

+
+ +

+ Please activate JavaScript to enable the search + functionality. +

+
+ +
+ +
+ +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 0000000000..928cb6e68b --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({docnames:["contact","dev/developer-guide","dev/index","dev/testing-with-docker","dev/writing-analysis-jobs","dev/writing-intel-modules","index","info","install","modules/_cartography-metadata/schema","modules/aws/config","modules/aws/index","modules/aws/permissions-mapping","modules/aws/schema","modules/azure/config","modules/azure/index","modules/azure/schema","modules/bigfix/config","modules/bigfix/index","modules/bigfix/schema","modules/crowdstrike/config","modules/crowdstrike/index","modules/crowdstrike/schema","modules/crxcavator/config","modules/crxcavator/index","modules/crxcavator/schema","modules/cve/config","modules/cve/index","modules/cve/schema","modules/digitalocean/config","modules/digitalocean/index","modules/digitalocean/schema","modules/duo/config","modules/duo/index","modules/duo/schema","modules/gcp/config","modules/gcp/index","modules/gcp/schema","modules/github/config","modules/github/index","modules/github/schema","modules/gsuite/config","modules/gsuite/index","modules/gsuite/schema","modules/index","modules/jamf/index","modules/jamf/schema","modules/kubernetes/config","modules/kubernetes/index","modules/kubernetes/schema","modules/lastpass/config","modules/lastpass/index","modules/lastpass/schema","modules/okta/config","modules/okta/index","modules/okta/schema","modules/pagerduty/config","modules/pagerduty/index","modules/pagerduty/schema","modules/semgrep/config","modules/semgrep/index","modules/semgrep/schema","ops","usage/drift-detect","usage/index","usage/samplequeries","usage/schema","usage/tutorial"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":4,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":3,"sphinx.domains.rst":2,"sphinx.domains.std":2,sphinx:56},filenames:["contact.md","dev/developer-guide.md","dev/index.rst","dev/testing-with-docker.md","dev/writing-analysis-jobs.md","dev/writing-intel-modules.md","index.rst","info.md","install.md","modules/_cartography-metadata/schema.md","modules/aws/config.md","modules/aws/index.rst","modules/aws/permissions-mapping.md","modules/aws/schema.md","modules/azure/config.md","modules/azure/index.rst","modules/azure/schema.md","modules/bigfix/config.md","modules/bigfix/index.rst","modules/bigfix/schema.md","modules/crowdstrike/config.md","modules/crowdstrike/index.rst","modules/crowdstrike/schema.md","modules/crxcavator/config.md","modules/crxcavator/index.rst","modules/crxcavator/schema.md","modules/cve/config.md","modules/cve/index.rst","modules/cve/schema.md","modules/digitalocean/config.md","modules/digitalocean/index.rst","modules/digitalocean/schema.md","modules/duo/config.md","modules/duo/index.rst","modules/duo/schema.md","modules/gcp/config.md","modules/gcp/index.rst","modules/gcp/schema.md","modules/github/config.md","modules/github/index.rst","modules/github/schema.md","modules/gsuite/config.md","modules/gsuite/index.rst","modules/gsuite/schema.md","modules/index.rst","modules/jamf/index.rst","modules/jamf/schema.md","modules/kubernetes/config.md","modules/kubernetes/index.rst","modules/kubernetes/schema.md","modules/lastpass/config.md","modules/lastpass/index.rst","modules/lastpass/schema.md","modules/okta/config.md","modules/okta/index.rst","modules/okta/schema.md","modules/pagerduty/config.md","modules/pagerduty/index.rst","modules/pagerduty/schema.md","modules/semgrep/config.md","modules/semgrep/index.rst","modules/semgrep/schema.md","ops.md","usage/drift-detect.md","usage/index.rst","usage/samplequeries.md","usage/schema.md","usage/tutorial.md"],objects:{},objnames:{},objtypes:{},terms:{"0":[4,13,16,19,22,25,37,40,41,58,62,63,66,67],"00":[19,43,66,67],"01":[19,23,43,66],"04":[19,43,66],"05":67,"05t17":[43,66],"06":19,"0652c2b6dede589e805156925353bffc72da6c2b":5,"06t18":19,"07":19,"096":[43,66],"1":[1,4,5,10,13,22,25,35,37,40,41,62,63,66,67],"10":[10,19,22,41,63,67],"100":[4,5,37,52,66],"1000":4,"106":19,"11":[1,8],"123":67,"1234":[37,66],"12345":[37,66],"127":62,"128":[13,19,66],"1569022981":1,"16":23,"160":[13,66],"16384":19,"1652400141863":67,"168":19,"1688605272":67,"17":10,"17763":19,"1809":19,"192":19,"19t15":19,"2":[1,4,5,10,13,19,35,40,43,63,66],"200":65,"2010":[43,66],"2012":10,"2019":[6,7],"2020":23,"2021":19,"2022":[19,67],"2023":19,"215":19,"22":67,"2300":19,"23z":19,"25":19,"250":63,"251":63,"252":63,"253":63,"254":63,"255":[13,63,66],"2fa":34,"3":[4,5,8,40,63,65,66],"30":[22,43,66],"3339":[37,66],"3406":19,"4":[1,5,8,40,43,63,66],"4217":[13,66],"5":[5,8,53,63],"50":19,"52":[19,67],"5218":19,"53":[13,66],"54":19,"55":19,"6":[37,66],"60":22,"61":62,"65535":[37,66],"7":[19,34],"7281227":41,"7474":67,"758":[9,66],"7687":[1,3,5,8,67],"8":[8,41],"8125":62,"8601":[13,43,66],"8d60311a10156cd8aa16de7e1fe3e109cc3eca0f":5,"90":22,"987654":[37,66],"\u2139":[1,5,64],"boolean":[13,19,31,66],"byte":[13,16,66],"case":[5,13,58,63,66],"catch":5,"class":[5,13,34,37,66],"const":67,"default":[1,3,4,8,10,12,13,16,35,37,40,58,62,66],"do":[4,5,10,13,35,64,66],"export":[1,3,8,41],"final":[4,5,8,63],"float":[22,31,66],"function":[1,4,5,11,13,22,37,66],"import":[1,2,13,25,38,40,41,58,63,66],"int":5,"long":[1,8,58,66],"new":[2,10,13,29,31,41,63,66,67],"null":[4,5,13,34,52,58,66],"public":[4,13,16,37,38,40,66,67],"return":[1,4,5,13,34,58,63,65,66,67],"short":[5,13,58,61,66],"super":[43,66],"switch":67,"throw":65,"true":[4,5,13,16,31,34,37,40,43,58,63,65,66,67],"try":[1,63],"var":[3,14,17,20,23,29,32,38,41,50,53,56,59],"while":[1,13,37,66],A:[5,13,16,19,28,31,34,37,40,43,58,61,62,64,66,67],AND:4,AS:[5,65,67],And:[5,67],As:[4,5,12,13,35,43,63,66],At:62,BY:65,But:4,By:[1,5],For:[1,5,8,9,10,13,37,38,43,66,67],IN:4,IS:[4,5],If:[1,4,5,8,12,13,20,26,31,34,35,37,38,40,43,53,58,65,66,67],In:[4,5,10,13,35,37,58,63,66,67],Is:[34,43,66],It:[5,6,7,10,12,13,37,63,66],Its:[9,66],NOT:[4,5,37,66],No:[41,58,66],Not:[13,34,66],ON:5,ONE:34,On:[3,5,10,13,19,34,66],One:[4,8,13,22,34,66],Or:8,The:[1,2,8,9,10,11,12,13,15,16,18,19,21,22,24,25,27,28,30,31,33,34,36,37,38,39,40,42,43,46,48,49,51,53,54,55,57,58,60,61,63,66,67],Then:67,There:[4,5,10],These:[5,13,40,43,66,67],To:[1,4,5,13,43,62,63,66,67],WITH:[4,5,13,66],With:[5,65],_:[4,5,9,13,41,66],__comment:4,__comment__:4,__future__:41,__main__:1,__name__:1,_blank:67,_integr:[58,66],_layer:[58,66],_of:[58,66],_process_access_polici:[13,66,67],_rule:[58,66],_sync_one_account:1,_vendor:[58,66],_with:[58,66],ab:19,abcd:19,abil:[58,66],abl:[1,4,5,35,67],about:[5,6,7,9,13,34,43,58,65,66,67],abov:[1,4,5,13,37,38,66,67],absract:12,accept:[5,13,41,43,66],accepter_cidr:[13,66],accepter_region:[13,66],accepter_vpc:[13,66],access:[2,5,10,11,12,13,16,29,34,35,37,40,41,47,52,53,58,63,64,66],accessconfig:[37,66],accesskeyid:[13,66],accessti:[16,66],accesstierchangetim:[16,66],accesstierstatu:[16,66],accomplish:5,accord:[13,66],accordingli:62,account:[5,8,9,13,16,22,29,30,31,35,37,41,43,50,52,55,58,63,64,66],account_id:[13,31,66],accountaccesskei:64,accountid:[5,10,53],accountname1:10,accountname2:10,accountoffertyp:[16,66],accout:52,acknowledg:[58,66],acknowledgement_timeout:[58,66],acl:[11,13,16,66],acp:[13,66],across:[1,5,13,16,37,40,64,66],act:[13,66],action:[4,10,13,16,31,40,66],actionrequir:[16,66],activ:[13,22,31,34,55,66],activation_id:[13,66],activedirectorypath:19,actively_us:22,actual:[1,4,5,9,25,37,66,67],ad:[4,5,13,14,16,31,63,66,67],add:[1,4,5,10,23,37,63,66,67],add_stag:1,addit:[1,2,13,25,37,66],address:[13,16,22,25,28,31,34,37,41,43,58,66,67],adjust:[13,62,66,67],admin:[32,34,40,41,43,52,66],admin_cr:[43,66],admininistr:[43,66],administ:[16,53,66],administered_bi:[16,66],administr:[16,34,43,55,66],administratortyp:[16,66],advanc:[58,66],advertis:[13,37,66],aes256:67,affect:[13,66],afford:5,after:[1,3,4,13,34,58,66],ag:[13,66],again:[4,13,66],against:[1,13,16,66],agent:[13,19,22,34,59,66],agent_connect:[13,66],agent_update_statu:[13,66],agent_vers:[13,22,66],agenttyp:19,agentvers:19,aggreg:67,agreed_to_term:[43,66],agreement:[43,66],ahead:[37,66],aid:22,aim:[6,7],alert:[16,58,66],alert_cr:[58,66],alert_grouping_parameters_typ:[58,66],algorithm:[13,66],alia:[13,16,34,43,66],alias1:34,alias2:34,alias3:34,alias4:34,alias:[11,13,16,34,63,66],aliasnam:[13,66],all:[1,2,4,6,7,8,10,12,13,14,16,31,34,35,37,38,40,43,61,63,64,66],alloc:[13,66],allocated_storag:[13,66],allocatedstorag:[13,66],allocation_id:[13,66],allow:[4,5,10,12,13,16,37,41,63,66,67],allow_dns_resolution_from_remote_vpc:[13,66],allow_egress_from_local_classic_link_to_remote_vpc:[13,66],allow_egress_from_local_vpc_to_remote_classic_link:[13,66],allowed_bi:[37,66],allowedhead:[16,66],allowedmethod:[16,66],allowedorigin:[16,66],alreadi:[1,4,5,67],also:[3,4,5,10,12,13,34,37,62,66,67],although:4,alwai:[13,34,37,63,66],amazon:[8,13,66],amazonaw:63,amazoncustomerbyemail:[13,66],amazonecr:[13,66],amazoninspector2readonlyaccess:10,ami:[11,13,66],among:[13,37,66],amount:[13,16,66],an:[1,2,3,6,7,8,10,12,13,14,16,17,20,23,29,31,34,35,37,38,40,41,43,50,52,53,55,56,58,59,61,62,63,65,66,67],analysi:[2,52,61,63,64],analyt:[16,66],analyticalttl:[16,66],analyz:[10,14,17,20,23,26,29,32,35,38,47,50,53,56,67],android:34,angri:4,ani:[1,2,5,12,13,16,34,37,49,62,63,64,66],anonym:[13,64,66],anonymous_access:[13,65,66,67],anonymous_act:[13,66,67],anoth:[5,13,43,63,66],answer:[41,67],anyon:[4,6,7],anyth:10,api:[5,6,7,10,11,13,20,23,29,32,34,38,40,41,43,50,53,56,58,59,61,66,67],api_describeimagescanfind:[13,66],api_imageidentifi:[13,66],apigatewayclientcertif:64,apigatewayresourc:64,apigatewayrestapi:64,apigatewaystag:64,apirefer:[13,66],app:[13,34,41,55,59,66],app_product_name_vers:22,apparmor:[13,66],appear:[13,66],append:67,appid:14,appl:34,appli:[4,13,16,35,37,40,43,66,67],applic:[13,25,34,35,43,52,54,55,64,66,67],applied_on:[13,66],applies_to:[13,66],appropri:[5,23,43,66],approv:[16,66],approxim:[16,66],ar:[0,1,4,5,8,10,12,13,16,20,26,35,37,38,40,43,52,53,55,62,63,64,66],arbitrari:[37,66],architectur:[13,66],archiv:[13,31,37,40,66],area:[6,7],arg:[2,17,32,59,67],argument:[2,8,23],argv:1,arm:[8,16,66],arn:[5,10,13,66,67],around:[5,8],arrai:[13,31,55,63,66],arriv:[13,66],articl:[13,66,67],ask:[5,63,67],asset:[4,6,7,8,10,14,19,35,37,66,67],assign:[13,28,35,37,43,49,55,66],assignipv6addressoncr:[13,66],associ:[5,13,16,22,34,37,43,58,62,66],associate_public_ip_address:[13,66],associated_with:[13,16,66],association_id:[13,66],association_statu:[13,66],assum:[5,10,11,13,66],assumerol:10,assumpt:[6,7,13,66],asynchron:[13,66],attach:[10,13,14,16,31,34,35,37,52,58,66,67],attached_to:[13,16,66],attached_to_ec2_inst:[13,66],attachments_statu:[13,66],attack:[6,7,28],attack_complex:28,attack_vector:28,attempt:[5,47],attribut:[4,5,34,67],audit:[13,16,66],audit_log:[13,66],augment:[13,66,67],aurora:[13,66],auth:[1,14,38,41],auth_en:[1,8],auth_json:[38,41],auth_provider_x509_cert_url:41,auth_uri:41,auth_url:41,authent:[8,13,14,16,34,35,37,40,41,55,66,67],authn:34,author:[5,41],authorit:[37,66],authorization_url:41,auto:[13,34,37,66],auto_create_subnetwork:[37,66],auto_enable_control:[13,66],auto_minor_version_upgrad:[13,66],auto_resolve_timeout:[58,66],auto_termin:[13,66],autom:[2,6,7,13,66],automat:[5,13,16,47,53,58,63,66],autosc:11,autoscaleset:[16,66],autoscaling_rol:[13,66],autoscalinggroup:[4,64],avail:[13,16,22,28,34,37,62,66,67],availability_impact:28,availability_zon:[13,66],availability_zone_id:[13,66],availabilityzon:[13,16,66],available_ip_address_count:[13,66],avatar:[58,66],avatar_url:[58,66],averageevaluationcycl:19,avoid:[62,67],aw:[1,3,4,5,8,22,37,53,63,64],awar:5,aws_access_kei:[13,66],aws_config_fil:[8,10],aws_ec2_asset_exposur:4,aws_id:5,aws_max_attempt:10,aws_profil:8,aws_retry_mod:10,aws_update_tag:5,awsaccount:[5,9,64,65,67],awscidrblock:64,awsconfigdeliverychannel:64,awsconfigrul:64,awsconfigurationrecord:64,awsdnsrecord:[64,67],awsdnszon:[64,67],awsgroup:64,awsinspectorfind:64,awsinspectorpackag:64,awsinternetgatewai:64,awsipv4cidrblock:64,awsipv6cidrblock:64,awslambda:64,awslambdaeventsourcemap:64,awslambdafunctionalia:64,awslambdalay:64,awspeeringconnect:64,awspolici:[12,64],awspolicystat:[12,64],awsprincip:[12,64],awsrol:[53,64],awssecretsmanag:[13,66],awstag:64,awstransitgatewai:64,awstransitgatewayattach:64,awsus:64,awsvpc:64,az:[13,14,66],azur:64,azure_client_id:14,azure_client_secret:14,azure_tenant_id:14,azurecdbprivateendpointconnect:64,azurecosmosdbaccount:64,azurecosmosdbaccountfailoverpolici:64,azurecosmosdbcassandrakeyspac:64,azurecosmosdbcassandrat:64,azurecosmosdbcorspolici:64,azurecosmosdbloc:64,azurecosmosdbmongodbcollect:64,azurecosmosdbmongodbdatabas:64,azurecosmosdbsqlcontain:64,azurecosmosdbsqldatabas:64,azurecosmosdbtableresourc:64,azurecosmosdbvirtualnetworkrul:64,azuredatabasethreatdetectionpolici:64,azuredatadisk:64,azuredisk:64,azureelasticpool:64,azurefailovergroup:64,azureprincip:64,azurerecoverabledatabas:64,azurereplicationlink:64,azurerestorabledroppeddatabas:64,azurerestorepoint:64,azureserveradadministr:64,azureserverdnsalia:64,azuresnapshot:64,azuresqldatabas:64,azuresqlserv:64,azurestorageaccount:64,azurestorageblobcontain:64,azurestorageblobservic:64,azurestoragefileservic:64,azurestoragefileshar:64,azurestoragequeu:64,azurestoragequeueservic:64,azurestoraget:64,azurestoragetableservic:64,azuresubscript:64,azureten:64,azuretransparentdataencrypt:64,b64encod:[38,41],back:[4,13,66,67],backend:[37,66],background:[9,66],backtrack:[13,66],backtrack_consumed_change_record:[13,66],backtrack_window:[13,66],backup:[13,16,66],backup_retention_period:[13,66],backupretentionperiod:[13,66],balanc:[11,13,49,64,66,67],bar:67,bartsimpson:19,base64:[38,41],base64encodedkei:3,base:[1,5,8,13,22,23,26,31,37,53,61,64,66],base_scor:[22,28],base_sever:28,baselin:63,bash:[3,14],basic:[4,5,11,13,16,37,66],basic_auth:[37,66],batch:[13,66],batchgetitem:12,batchsiz:[13,66],bear:8,becaus:[4,5,13,35,66,67],been:[5,13,31,34,37,43,66,67],befor:[2,13,16,34,58,61,66],began:[13,66],begin:[13,66],behalf:[13,66],behind:[6,7],being:[3,6,7,13,58,66],believ:5,belong:[13,16,31,34,37,66],below:[1,5,13,41,63,66],benefici:1,benefit:[5,6,7],besrelayselectionmethod:19,besrootserv:19,best:[2,13,66],better:[5,6,7],between:[4,5,6,7,12,13,22,34,66,67],beyond:[16,66],bi:65,bigfix:18,bigfix_password_env_var:17,bigfixroot:19,bill:[13,37,66],bind:3,bio:[19,22,58,66],biometr:34,bios_manufactur:22,bios_vers:22,bisectbatchonfunctionerror:[13,66],bit:[13,66],blackberri:34,blank:[13,34,66],blob:[5,16,66],block:[13,14,31,37,38,41,66],block_associ:[13,66],block_public_acl:[13,66,67],block_public_polici:67,block_stat:[13,66],blue:[6,7],bold:66,bolt:[1,3,8,67],bookmark:[63,67],bookmarklet:64,boot:[13,66],bootmod:[13,66],both:[5,8,12,37,58,66],boto3:65,botocor:1,bottom:67,bound:[5,13,16,66],branch:[39,40,66],breaker:[13,66],bridg:[13,66],broad:[6,7],browser:[16,34,66,67],bsidessf:[6,7],bubbl:5,bucket:[11,13,37,64,66],bucket_key_en:[13,66,67],build:[3,8,13,22,34,41,66,67],build_custom_sync:1,build_default_sync:4,build_ingestion_queri:5,built:[5,10,12,13,14,66],bunch:4,bypass:34,c4:63,c:[16,66],ca:[13,66],ca_certificate_identifi:[13,66],cach:[13,16,37,66],cacheclusteren:[13,66],cacheclusterstatu:[13,66],calcul:[12,13,66],call:[4,5,6,7,10,13,14,16,23,25,26,29,38,41,58,66],came:5,can:[1,3,4,5,6,7,8,10,12,13,16,20,22,26,31,34,35,37,38,40,43,47,49,50,53,55,56,58,61,62,63,64,66],can_queri:12,can_read:12,can_read_from:[16,66],can_write_from:[16,66],cannot:[13,37,43,66],canon:[40,66],canonic:[40,66],canonicalhostedzonenam:[13,66],canonicalhostedzonenameid:[13,66],canonicalus:[13,66],capabl:[16,34,66],capac:[13,66],capacity_provid:[13,66],capacity_provider_nam:[13,66],capacityrebal:[13,66],caption:67,car:66,card:67,carri:5,carrier:[13,66],carrier_ip:[13,66],cartographi:[0,2,3,10,12,13,14,17,20,23,26,29,32,35,37,38,40,41,47,50,53,56,59,63,64],cartographyassumerolepolici:10,cartographynodeproperti:5,cartographynodeschema:5,cartographyrelproperti:5,cartographyrelschema:5,cassandra:[16,66],categor:[25,66],caus:[5,13,66],cd:[1,19],center:[16,43,66],cert:41,certain:[1,63],certif:[11,13,34,66],cfg:[40,66],chain:61,chang:[1,3,5,13,20,22,25,26,43,52,55,58,63,66,67],change_password_at_next_login:[43,66],changem:41,channel:[11,13,66],charact:[13,43,66],character_set_nam:[13,66],check:[13,34,61,66],child:[43,66],choic:[5,29,38,41],chrome:[23,24,25,64,66],chromeextens:[64,65],ci:[59,61],cid:[22,50],cidr:[13,37,66],cidr_block:[13,66],cidrblock:[13,66],cipher:[13,66],circuit:[13,66],clarif:5,clarifi:5,classic:[13,66],classiclink:[13,66],classif:[13,66],claus:[4,67],clean:2,cleanup:2,cleanup_job:5,cli:[1,5,8,13,14,17,20,26,29,32,38,41,47,50,53,56,59,66],click:[29,67],client:[5,13,14,20,41,58,66],client_id:41,client_secret:41,clientcertificateid:[13,66],clone:[1,13,66],clone_group_id:[13,66],close:22,closed_timestamp:22,cloud:[13,34,35,37,41,61,66],cloudtrail:[13,66],cloudwatch:[13,66],cluster:[5,11,13,37,47,48,49,66],cluster_arn:[13,66],cluster_create_tim:[13,66],cluster_data:5,cluster_identifi:[13,66],cluster_ipv4cidr:[37,66],cluster_revision_numb:[13,66],cluster_statu:[13,66],clusterarn:5,clusterip:[49,66],cmd:67,cmk:[13,66],cn:19,cname:[13,66],coalesc:4,code:[1,4,5,8,13,14,38,41,61,66,67],codebas:1,codes:[13,66],codesha256:[13,66],collabor:[40,66],collat:[16,66],collect:[16,34,66],collectionnam:[16,66],color:[58,66,67],column:61,com:[1,4,5,9,13,19,35,37,38,41,43,63,66,67],combin:[12,13,25,31,66],come:[13,46,66],comma:[13,66],command:[2,3,8,12,13,62,63,66],commandlin:[2,23,40,66],comment:[1,13,66],commit:[1,13,66],common:[13,66],common_job_paramet:5,commun:[1,8,13,37,66],compani:[37,40,66],compar:[13,63,66],compat:[13,66],complet:[1,5,13,16,43,66],complex:[4,28],complianceresourceid:[13,66],compon:[25,66],compos:[1,2,61],composit:61,compress:[13,66],comput:[5,13,16,18,19,30,37,46,63,66],computer_nam:[13,16,66],computer_sid:34,computernam:19,computertyp:19,conain:34,concaten:[13,25,66],concept:[2,4],concret:[13,66],concurr:[13,66],condit:[13,37,61,66],conf:[1,8],confidenti:28,confidentiality_impact:28,config:[3,5,8,10,11,13,37,38,66],config_snapshot_delivery_properties_delivery_frequ:[13,66],configur:[2,8,11,13,16,22,34,37,62,66],configured_with:[16,66],confirm:61,conflict:[16,66],conflictresolutionpolicymod:[16,66],conjunct:[37,66],connect:[4,5,13,16,22,37,61,64,66],connectivity_at:[13,66],connector:[16,66],connectoroff:[16,66],connecturl:67,consent:41,consid:[13,62,66],consist:[5,12,13,16,66],consol:[13,41,43,66,67],consolid:[6,7],constant:[58,66],constraint:[13,66],constructor:5,contact:[34,43,66],contain:[5,8,10,12,13,16,22,31,34,35,37,40,48,49,55,61,62,63,65,66],container:[13,66],container_instance_arn:[13,66],containerinsight:[13,66],content:[13,38,41,63,66,67],content_based_dedupl:[13,66],context:[49,66],continu:[5,13,63,66,67],contoso:67,contrast:[13,66],control:[13,35,53,66],convei:[9,66],convent:5,cooldown:[13,66],coordin:[13,66],copi:[5,13,66],cor:[16,66],core:[5,6,7,13,34,66],coretto:8,corp:19,correct:3,correctli:10,cosmo:[16,66],cosmosdb:[15,16,66],could:[13,66],count:[4,13,25,43,65,66,67],counter:[13,66],coupl:[63,67],cover:[4,10,37,66],coverag:[11,15,18,21,24,27,30,33,36,39,42,48,51,54,57,60],cpu:[13,19,22,34,66],cpu_id:34,cpu_signatur:22,creat:[1,4,5,10,12,13,14,16,19,22,29,31,34,35,37,38,40,41,43,52,53,55,58,59,62,63,66],create_bi:[55,66],create_index:1,create_tim:[13,66],createactiv:[13,66],created:[13,66],created_at:[13,31,37,49,58,66],created_bi:[13,66],created_d:[13,66],created_from:[13,66],created_tim:[13,66],created_timestamp:[13,22,66],createdat:[40,66],createdbinstancereadreplica:[13,66],createdbsnapshot:[13,66],createdd:[13,66],createdtim:[13,66],createopt:[16,66],createtim:[13,66],creation:[5,13,16,34,37,49,55,66],creation_tim:[43,66],creationd:[13,16,66,67],creationtim:[16,66],cred:[32,41],credenti:[1,2,3,10,23,29,34,35,38,41,52],credential_nam:34,credential_sourc:10,critic:[13,22,61,65,66],criticalupd:[13,66],cronjob:62,cross:[13,66],crowdstrike_first_seen:22,crowdstrike_last_seen:22,crxcavat:[25,64,66],crxcavator_last_upd:[25,66],crxcavtor:64,csp:[25,66],cumbersom:63,currenc:[13,66],currencycod:[13,66],current:[0,4,5,13,19,22,25,31,37,58,66],current_aws_account_id:5,current_master_vers:[37,66],custom:[2,3,4,13,22,34,37,41,43,64,66],custom_ami_id:[13,66],custom_sync:1,customer_id:[43,66],customer_owned_ip:[13,66],customer_owned_ipv4_pool:[13,66],customerid:[43,66],cve:[21,61,64],cve_id:[13,22,61,66],cve_schema:61,cvssv3:28,cwe:28,cypher:[2,63,67],d:[1,3,5,53,67],daemon:[13,66],dai:[13,16,58,63,66],daili:[13,66],data:[4,5,8,10,13,16,25,26,27,28,29,37,38,40,41,62,64,65,66],databas:[4,6,7,8,13,16,66],database_encrypt:[37,66],database_nam:[13,66],databaseid:[16,66],databasenam:[16,66],dataclass:5,dataencryptionkeyid:[13,66],date:[4,13,16,19,22,25,28,29,31,34,37,43,55,58,61,66],date_ad:34,datetim:[13,19,66],db:[13,16,66],db_cluster_identifi:[13,66],db_cluster_resource_id:[13,66],db_instance_class:[13,66],db_instance_identifi:[13,66],db_instance_port:[13,66],db_name:[13,66],db_parameter_group:[13,66],db_snapshot_identifi:[13,66],dbcluster:[13,66],dbi_resource_id:[13,66],dbinstanc:[13,66],dbm:[1,8],dbname:[13,66],dbserver1:[13,66],dbsnapshot:[13,66],dbsubnetgroup:64,dc:19,ddthh:[43,66],dead:[11,13,66],debug:5,decid:5,decis:5,declar:4,decor:[66,67],decrypt:[13,66],dedic:[13,66],dedupl:[13,66],deduplication_scop:[13,66],def:[1,5],default_encrypt:[13,66,67],default_for_az:[13,66],default_kms_key_nam:[37,66],default_rol:[58,66],default_vers:[13,66],default_version_numb:[13,66],defaultbranch:[40,66],defaultbranchid:[40,66],defaultconsistencylevel:[16,66],defaultcooldown:[13,66],defaultencryptionscop:[16,66],defaultinstancenam:[13,66],defaultttl:[16,66],defin:[2,3,8,12,13,27,37,53,64,66],defined_in:[37,66],definit:[5,13,66],delai:[13,66],delay_second:[13,66],deleg:[37,41,43,66],delet:[1,5,13,16,34,37,38,49,62,66],deleteautoscalinggroup:[13,66],deleted_at:[49,66],deleted_d:[13,66],deletedtim:[16,66],deleteontermin:[13,66],deletesecret:[13,66],deletion_protect:[13,66],deletiond:[16,66],deliv:[13,66],deliveri:[11,13,66],deni:[13,37,66],denied_bi:[37,66],denot:[4,22,40,66],dep:65,depend:[3,6,7,13,58,61,64],dependency_fil:61,dependency_file_url:61,dependency_fix:61,deploi:[13,31,66],deploy:[13,60,61,66],deployment_config_circuit_breaker_en:[13,66],deployment_config_circuit_breaker_rollback:[13,66],deployment_config_maximum_perc:[13,66],deployment_config_minimum_healthy_perc:[13,66],deploymentid:[13,66],deprec:34,depth:67,deregist:[13,66],deregistered_at:[13,66],deriv:[5,13,37,49,66],desc:34,describ:[4,5,13,31,37,40,63,66,67],describe_image_scan_find:[13,66],describeregion:10,describesnapshot:[13,66],descript:[9,13,16,19,22,25,28,31,34,37,40,43,46,49,52,55,58,61,66],description_en:28,design:5,desir:[13,62,66],desired_count:[13,66],desired_statu:[13,66],desiredcapac:[13,66],desktop:19,destin:[13,37,66],detach:[5,13,66],detail:[1,8,10,11,13,35,43,62,66],detect:[16,34,47,64,66],detectdrift:63,determin:[4,13,37,43,58,62,66,67],dev:[13,66],devdev:[13,66],develop:[2,5,25,41,43,66],devic:[13,22,34,66],device_id:34,device_identifi:34,device_identifier_typ:34,device_nam:34,device_udid:34,device_usernam:34,device_username_typ:34,devicetyp:19,diagnos:[13,66],dial:34,dict:5,dictlist:5,did:[9,66],diff:64,differ:[1,5,10,12,13,40,66],differenti:[6,7],difficult:5,digest:[13,62,66],digitalocean:[29,64],direct:[4,5,13,37,43,63,66],direct_members_count:[43,66],direction:5,directli:[1,5,13,64,66],directmemberscount:[43,66],directori:[3,4,13,22,34,41,43,63,66],directory_v1:41,disabl:[1,3,13,16,34,37,40,52,58,66],disable_api_termin:[13,66],disable_network:[13,66],disabledalert:[16,66],disableexecuteapiendpoint:[13,66],disablekeybasedmetadatawriteaccess:[16,66],disallow:[37,66],discard:[13,66],disconnect:[5,16,66],discov:[5,6,7,13,16,22,25,28,31,34,37,43,49,55,58,61,66],discoveri:41,discuss:5,disk:[13,16,66],disk_encryption_statu:34,disksizegb:[16,66],displai:[13,43,66],displaynam:[13,37,66],distinct:[65,67],distribut:[13,66],distro:[13,66],dn:[13,16,36,37,55,66,67],dns_name:[37,66],dns_points_to:[13,66],dns_search_domain:[13,66],dns_server:[13,66],dnsname:[13,19,65,66],dnsrecord:[16,64,67],dnszone:[64,67],doaccount:64,doc:[3,4,5,8,13,25,29,35,37,62,66,67],docker:[1,2,8,13,49,66],docker_security_opt:[13,66],document:[3,4,5,13,20,37,38,41,53,56,62,66,67],documentendpoint:[16,66],dodroplet:64,doe:[5,8,10,25,34,37,58,66],doesn:[1,4,13,37,43,66],domain:[11,13,16,22,34,37,41,43,55,66,67],domain_sid:34,domainid:[13,66],don:[1,4,5,13,66,67],doproject:64,down:[13,37,47,66],download:[8,25,41,66],drain:[13,66],draw:5,drift:64,drift_detection_directori:63,drive:34,drop:[13,16,66],droplet:[30,31,66],droplet_limit:[31,66],due:[16,66],dumb:5,dump:[38,41],duplic:[5,43,66],duplicate_keyfingerprint:[13,66],durat:[13,16,58,66],dure:[13,62,66],dynamodb:[11,12],dynamodbt:[12,64],e6ada9a1a741b83a34c1c3207515a1863debeeb9:5,e:[1,3,5,10,13,14,16,25,37,40,49,55,61,62,63,65,66],each:[4,5,8,10,12,13,31,34,37,38,47,58,62,63,66],earlier:67,earliest:[13,16,66],earliest_backtrack_tim:[13,66],earliest_restorable_tim:[13,66],easi:65,easier:[1,5,62,63],easiest:4,easili:4,easily_access:22,east:10,eb:[11,13,66],ebs_optim:[13,66],ebsoptim:[13,66],ebssnapshot:64,ebsvolum:64,ec2:[2,5,10,11,13,37,64,66],ec2_instance_id:[13,66],ec2config:[13,66],ec2imag:64,ec2inst:[4,63,64,65,67],ec2instancemetadata:10,ec2keypair:64,ec2privateip:64,ec2reserv:64,ec2reservedinst:64,ec2securitygroup:[4,64,67],ec2subnet:64,ec:[13,66],ecc_kms_key_id:[13,66],ecc_log:[13,66],ecc_log_configuration_cloud_watch_encryption_en:[13,66],ecc_log_configuration_cloud_watch_log_group_nam:[13,66],ecc_log_configuration_s3_bucket_nam:[13,66],ecc_log_configuration_s3_encryption_en:[13,66],ecc_log_configuration_s3_key_prefix:[13,66],ecosystem:61,ecr:[13,66],ecrimag:64,ecrrepositori:64,ecrrepositoryimag:64,ecrscanfind:64,ecsclust:64,ecscontain:64,ecscontainerdefinit:64,ecscontainerinst:64,ecsservic:64,ecstask:64,ecstaskdefinit:64,edg:[13,40,65,66],edit:[1,8,16,43,66,67],efa:[13,66],effect:[10,13,34,37,58,66],egress:[37,66],eight:34,either:[5,13,34,35,37,40,66,67],ek:[13,66],eksclust:64,elast:[11,13,16,66,67],elastic_ip_address:[13,66],elasticipaddress:64,elasticpoolid:[16,66],elasticsearch:[11,13,66,67],elasticsearch_cluster_config_dedicatedmastercount:[13,66],elasticsearch_cluster_config_dedicatedmasteren:[13,66],elasticsearch_cluster_config_dedicatedmastertyp:[13,66],elasticsearch_cluster_config_instancetyp:[13,66],elasticsearch_cluster_config_zoneawarenessen:[13,66],elasticsearch_vers:[13,66],elasticsearchdomainconfig:[13,66],elb:[13,63,64,66],elb_listen:[13,66],elblisten:[64,65],elbv2:[13,64,66,67],elbv2_listen:[13,66],elbv2listen:[64,65],element:[13,66],elev:[13,66],els:[8,41],email:[16,25,28,34,38,40,41,43,52,55,58,65,66],emailaddress:[16,66],emailadmin:[16,66],empti:[13,16,34,37,63,66],emr:[5,13,66],emrclust:[5,64],emrclusternodeproperti:5,emrclusterschema:5,emrclustertoawsaccount:5,emrclustertoawsaccountrelproperti:5,ena:[13,66],enabl:[5,6,7,13,16,19,26,31,34,37,40,41,43,53,58,62,65,66,67],enable_ecs_managed_tag:[13,66],enable_execute_command:[13,66],enableanalyticalstorag:[16,66],enableautomaticfailov:[16,66],enablecassandraconnector:[16,66],enabledprotocol:[16,66],enablefreeti:[16,66],enasupport:[13,66],encapsul:61,encod:[38,41],encourag:5,encrypt:[13,16,34,37,64,66],encryption_algorithm:[13,66,67],encryption_at_rest_options_en:[13,66],encryption_key_id:[13,66],end:[13,34,58,61,62,63,66],end_col:61,end_lin:61,endpoint:[16,33,34,37,38,49,64],endpoint_address:[13,66],endpoint_hostedzoneid:[13,66],endpoint_port:[13,66],endpoint_public_access:[13,66],enforc:[43,66],engin:[13,36,37,66],engine_mod:[13,66],engine_vers:[13,66],english:[2,28],enhanc:[4,13,66],enhanced_monitoring_resource_arn:[13,66],enjoi:4,enough:[4,6,7],enrich:64,enrol:[19,43,66],enrollmentdatetim:19,ensur:[1,4,5,10,14,35,62],enter:[13,41,66],enterpris:38,entir:[13,66],entiti:[37,58,66],entri:[4,13,66],entry_point:[13,66],entrypoint:3,env:[3,8,14,17,20,23,29,32,38,41,50,53,56,59],environ:[1,3,5,8,10,13,14,17,20,23,29,31,32,35,38,41,50,53,56,59,62,66],environment:41,ephemer:[13,66],ephemeral_storage_size_in_gib:[13,66],epkei:34,epoch:5,equival:5,error:[2,10,13,66],es:[13,34,66],escal:[57,58,66],escalation_polici:[58,66],esdomain:[64,67],essenti:[4,13,66],estim:[13,66],etag:[43,66],etc:[3,10],etcd:[37,66],evalu:[13,66],even:63,event:[13,16,66],eventsourcearn:[13,66],ever:[13,66],everi:[1,5,13,66],everyth:[40,66,67],evict:[16,66],eviction_polici:[16,66],evid:65,exact:[40,66],exampl:[1,2,5,8,9,12,13,19,37,38,43,64,65,66,67],exce:[13,66],exceed:[13,66],except:[4,5,13,37,66],exclud:[43,66],execut:[4,13,41,62,63,66,67],execution_role_arn:[13,66],execution_stopped_at:[13,66],exist:[1,5,9,16,34,66],exit:[1,13,66],exit_cod:[13,66],expect:[1,5],expir:[13,22,66],expirationd:[13,66],explain:[5,13,66],explan:5,explicitli:[4,5,8,13,66],exploit:[22,28],exploitability_scor:[22,28],explor:[6,7,13,66],expos:[4,6,7,13,16,37,64,66],exposed_internet:[4,13,37,63,65,66,67],exposed_internet_typ:[4,37,63,66],exposedhead:[16,66],exposur:[4,6,7,13,63,66],express:[13,16,66],ext:65,extend:[2,43,64,66],extens:[6,7,23,24,25,34,64,66],extension_id:[25,66],extern:[13,22,25,31,34,37,66],external_id:[55,66],external_ip:22,extra_index:5,extras_requir:[40,66],eyjvcmdhbml6yxrpb24ioibbeyj0b2tlbii6icjmywtldg9rzw4ilcaidxjsijogimh0dhbzoi8vyxbplmdpdgh1yi5jb20vz3jhcghxbcisicjuyw1lijogimzha2vvcmcifswgeyj0b2tlbii6icjzdglsbgzha2uilcaidxjsijogimh0dhbzoi8vz2l0ahvilmv4yw1wbguuy29tl2fwas9ncmfwahfsiiwgim5hbwuioiaizmfrzw9yzyj9xx0:38,f:[5,41],fabric:[13,66],face:[13,66,67],fact:4,factor:[34,40,54,55,66],factor_typ:[55,66],fail:[5,13,66],failov:[13,16,66],failovergroupid:[16,66],failoverprior:[16,66],fake:[5,67],fakeorg:38,faketoken:38,falcon:[20,22],fals:[1,13,34,37,65,66,67],famili:[13,66],family_nam:[43,66],faq:[43,66],far:8,fargat:[13,66],fashion:[6,7],fast:[2,13,66],faster:[5,66,67],fastrestor:[13,66],fc:41,fe80:19,featur:[1,6,7,31,43,55,58,66],fetch:10,fetch_token:41,few:4,field:[2,4,9,13,14,16,19,22,25,28,31,34,37,38,40,43,46,49,52,55,58,61,62,63,66,67],fifo:[13,66],fifo_queu:[13,66],fifo_throughput_limit:[13,66],file:[1,3,4,5,8,10,13,16,34,35,40,41,47,52,61,64,66],filenam:64,fill:[63,67],filter:[65,67],find:[1,4,5,13,50,59,60,61,62,66,67],fingerprint:[13,34,66],finish:1,firewal:[16,34,37,66],firewall_ingress:[37,66],firewall_partial_uri:[37,66],firewall_statu:34,first:[2,13,19,22,25,28,31,34,37,38,40,41,43,49,52,53,55,58,61,63,66,67],first_nam:[55,66],firstnam:34,firstseen:[2,13,16,19,22,25,28,31,34,37,40,43,49,52,55,58,61,66,67],fix:[13,16,61,66],fixedpric:[13,66],flag:[13,16,26,52,62,66,67],flat:[31,66],fleet:[13,66],flexibl:[6,7],floating_ip_limit:[31,66],flow:41,focus:[4,6,7],folder:[4,13,35,37,63,66],folderview:35,follow:[1,4,5,8,10,11,14,15,17,18,20,21,23,24,26,27,29,30,32,33,35,36,37,38,39,41,42,47,48,50,51,53,54,56,57,59,60,63,66,67],forc:[43,66],forcefulli:[13,66],foreign:[13,55,66],form:[28,34,37,40,43,52,58,66],format:[3,13,16,27,31,37,41,43,63,66],former:5,formfil:52,forward:[5,13,37,43,66],found:[1,4,13,22,37,66],found_in:61,fqdn:34,fr:41,free:[16,34,66],frequenc:[13,66],fresh:62,friendli:[13,16,37,46,66],from:[2,4,5,6,7,8,10,13,16,23,29,34,35,37,38,40,41,49,50,53,56,58,61,63,66,67],from_client_secrets_fil:41,from_node_schema:5,from_port:[13,66],fromport:[13,37,66],frontend:[6,7],frozen:5,fruit:4,fulfil:[13,66],full:[5,8,13,16,23,25,34,37,40,43,52,66,67],full_control:[13,66],fulli:[6,7,13,16,37,66],fullnam:[40,41,66],functionvers:[13,66],futur:[25,34,37,66],fw:[37,66],g:[5,10,13,14,25,37,40,41,43,49,55,61,62,65,66,67],gatewai:[11,13,37,66],gateway_address:[37,66],gather:[13,66],gb:[16,66],gce:35,gcp:[5,64],gcpbucket:64,gcpbucketlabel:64,gcpbucketlabel_:[37,66],gcpdnszone:64,gcpfirewal:64,gcpfolder:64,gcpforwardingrul:64,gcpinstanc:64,gcpiprul:64,gcpnetworkinterfac:64,gcpnetworktag:[5,64],gcpnicaccessconfig:64,gcporgan:64,gcpproject:[5,64],gcprecordset:64,gcpsubnet:64,gcpvpc:[5,64],gener:[4,5,6,7,13,14,20,23,29,34,37,38,53,56,58,63,66],genericnod:66,geo:[16,66],get:[1,2,4,8,16,35,37,41,43,50,63,66,67],getitem:12,getobject:12,getrecord:12,ghcr:62,gib:[13,66],gibibyt:[13,66],gigabyt:[16,66],git:[1,3,13,40,66],github:[1,3,5,9,13,29,52,62,64,67],github_kei:3,githubbranch:64,githuborgan:64,githubrepositori:[61,64,65],githubteam:64,githubus:64,giturl:[40,66],give:[5,13,63,66],given:[5,13,31,34,37,64,66],given_nam:[43,66],gke:[37,66],gkeclust:64,global:[5,11,13,34,37,43,66],gmail:[43,66],go:[8,10,12,41,63,67],goal:2,gold:19,good:[6,7,13,22,66],googl:[34,35,37,41,43,66],google_application_credenti:35,google_auth_oauthlib:41,googleapi:[37,41,66],googleapicli:41,googleusercont:41,gotten:5,gpu:[13,66],gpu_id:[13,66],grant:[10,11,12,13,64,66],grante:[13,66],granteeid:[13,66],granteeprincip:[13,66],granular:1,graph:[1,4,5,6,7,8,12,29,38,67],graphjob:5,graphql:38,greengrass:[13,66],group:[4,5,10,11,13,16,22,33,34,37,41,42,43,46,53,54,55,58,66,67],group_id:[9,13,34,66],group_typ:[9,66],groupid:[9,13,66],groupkei:[43,66],grouptyp:[9,66],gsuit:[24,52,64],gsuite_delegated_admin:41,gsuite_google_application_credenti:41,gsuitegroup:64,gsuiteus:[64,65],guarante:[4,13,66],guid:[2,5,8,10,41],guidelin:5,ha:[4,5,8,10,11,12,13,14,15,16,18,21,22,24,25,27,30,31,33,34,35,36,37,39,40,42,43,48,49,51,54,55,57,58,60,62,63,65,66,67],hand:5,handhold:67,handl:2,handler:[13,66],handoff:[58,66],happen:[9,66],hard:[13,16,34,66],hardwar:[13,34,66],hardware_seri:34,hardware_uuid:34,has_2fa_en:[40,66],has_certif:[13,66],has_contain:[13,49,66],has_container_definit:[13,66],has_container_inst:[13,66],has_cv:22,has_deadletter_queu:[13,66],has_duo_endpoint:34,has_duo_phon:34,has_duo_token:34,has_duo_web_authn_credenti:34,has_inform:[13,66],has_launch_config:[13,66],has_launch_templ:[13,66],has_namespac:[49,66],has_patch:[13,66],has_pod:[49,66],has_record:[37,66],has_secret:[49,66],has_servic:[13,49,66],has_target_service_account:[37,66],has_task:[13,66],has_task_definit:[13,66],has_vulner:22,hash:[13,66],hasimmutabilitypolici:[16,66],haslegalhold:[16,66],hasn:[13,66],have:[1,4,5,8,10,12,13,25,31,34,37,40,49,55,58,61,62,63,64,66],he:[13,66],header:[16,66,67],health:[13,34,66],health_app_client_vers:34,health_check_grace_period_second:[13,66],health_data_last_collect:34,health_statu:[13,66],healthcheckgraceperiod:[13,66],healthchecktyp:[13,66],healthi:[13,66],help:[4,6,7,8,10,13,37,43,62,63,66],helper:41,here:[0,1,4,5,8,9,13,34,62,63,66,67],hibern:[13,66],hibernationopt:[13,66],hidden:[6,7],hierarchi:[13,35,37,66],hierarchicalnamespac:[16,66],high:[13,22,49,61,65,66],higher:8,highest:[13,37,66],highli:65,histori:[3,13,66],hl:41,hnsenabl:[16,66],hold:[16,23,66],homepag:[40,66],hop:4,hope:4,host:[2,13,16,20,21,22,32,34,62,66],host_info_local_ip:22,hosted_zone_id:[13,66],hostedzon:[13,66],hostnam:[13,22,32,34,37,49,66],hostresourcegrouparn:[13,66],hour:[13,43,58,66],hourli:[13,66],how:[2,13,16,20,25,58,62,64,66],howev:[13,66],html:[13,66],html_url:[58,66],http:[4,5,9,13,16,23,35,37,38,41,43,66,67],hub:[10,11,13,66],human:[13,31,34,43,55,66],hypervisor:[13,66],i:[5,13,49,50,63,64,66],iam:[1,10,11,12,13,35,37,66,67],iam_config_bucket_policy_onli:[37,66],iam_database_authentication_en:[13,66],iam_instance_profil:[13,66],iam_instance_profile_arn:[13,66],iam_instance_profile_nam:[13,66],iam_password_polici:[13,66],iam_rol:[13,66],iaminstanceprofil:[13,66],icon:[25,66,67],id:[4,5,9,13,14,16,19,20,22,25,28,31,34,37,40,41,43,46,49,52,53,55,58,61,65,66,67],idea:[4,5],idempot:5,ident:[10,13,14,16,34,35,43,52,55,58,66,67],identif:[13,66],identifi:[5,6,7,13,16,22,28,31,34,37,40,49,58,61,63,66],identity_duo:34,identity_gsuit:[43,66],identity_lastpass:52,identity_okta:[55,66],identity_typ:[16,66],if_has_servic:[58,66],ignor:[3,13,43,58,66],ignore_public_acl:[13,66,67],ignoremissingvnetserviceendpoint:[16,66],imag:[3,8,13,16,31,49,66],image_digest:[13,66],image_id:[13,66],imageid:[13,49,66],immut:[13,66],immutabilitypolici:[16,66],impact:28,impact_scor:28,implement:[2,13,66,67],improv:[6,7],inact:[13,66],inbound:[4,13,37,66,67],inbound_account:[13,66],inbound_block:[13,66],inbound_group:[13,66],inbound_rang:[13,66],inbound_rul:[13,66],inbound_vpc:[13,66],incid:[58,66],incident_urgency_rule_during_support_hours_typ:[58,66],incident_urgency_rule_during_support_hours_urg:[58,66],incident_urgency_rule_outside_support_hours_typ:[58,66],incident_urgency_rule_outside_support_hours_urg:[58,66],incident_urgency_rule_typ:[58,66],includ:[1,2,4,5,12,13,22,31,40,43,61,66,67],include_in_global_address_list:[43,66],incomplet:5,increment:[5,16,66],indent:41,index:[1,2,4,11,13,16,66],indexingmod:[16,66],indic:[9,13,16,31,34,43,52,66,67],indirect:[13,66],indirectli:64,individu:[2,13,34,66],infeas:12,infinit:[16,66],info:[1,5,29,34,65],inform:[4,5,9,13,34,37,40,43,58,63,65,66],infrastructur:[6,7,13,63,66,67],ingest:[1,4,5,8,13,37,38,41,59,61,65,66],ingress:[37,49,66,67],ingress_host:[49,66],ingress_ip:[49,66],inherit:5,initi:[3,13,37,43,66],initial_vers:[37,66],inlin:[10,11,13,66],inline_polici:[13,66],innertext:67,input:41,input_paramet:[13,66],inscop:[13,66],insert:[37,43,66],insid:[13,61,66],insight:[13,66],inspector2:10,inspector:[13,66],instal:[1,13,25,34,37,41,64,66],install_requir:[40,66],installed_tim:[13,66],installedappflow:41,instanc:[1,2,5,8,10,11,13,16,20,22,31,35,37,38,40,62,64,66],instance_collection_typ:[13,66],instance_create_tim:[13,66],instance_fleet:[13,66],instance_group:[13,66],instance_id:[13,22,66],instance_initiated_shutdown_behavior:[13,66],instance_monitoring_en:[13,66],instance_nam:[37,66],instance_port:[13,66],instance_protocol:[13,66],instance_ten:[13,66],instance_typ:[13,66],instanceid:[13,65,66,67],instanceinform:[13,66],instancelifecycl:[13,66],instancenam:[37,66],instanceprivateipaddress:[13,66],instanceten:[13,66],instancetyp:[13,63,66],instanti:[13,66],instead:[13,62,64,66,67],instruct:[8,13,66],integ:[13,19,34,61,66],integr:[1,5,28,57,58,66],integrity_impact:28,intel:[2,3,4,8,13,47,66,67],intend:[58,66],inter:[13,66],interact:[13,28,66,67],interest:[1,63,67],interfac:[4,6,7,11,13,37,66,67],interface_typ:[13,66],intern:[13,19,31,37,65,66],internet:[2,11,13,37,64,66],intervent:[13,66],introduc:5,introduct:[13,66],intuit:[6,7],invalid:[55,66],invit:[58,66],invitation_s:[58,66],invoc:[13,66],invok:[1,13,66],inward:5,io:[23,25,34,62,66],iop:[13,66],iot:[13,66],ip:[4,11,22,31,37,43,49,64,67],ip_address:[13,31,37,66],ip_cidr_rang:[37,66],ip_owner_id:[13,66],ip_protocol:[37,66],ip_v6_address:[31,66],ip_whitelist:[43,66],ipaddress:19,ipc:[13,66],ipc_mod:[13,66],ippermissioninbound:[4,64],iprang:[4,13,16,64],iprul:[16,64],ipv4:[13,66],ipv6:[13,66],ipv6address:19,is_admin:[43,66],is_cluster_member_of:[13,66],is_default:[31,66],is_delegated_admin:[43,66],is_enforced_in_2_sv:[43,66],is_enrol:34,is_enrolled_in_2_sv:[43,66],is_latest_vers:[13,66],is_mailbox_setup:[43,66],is_read_replica_of:[13,66],is_site_admin:[40,66],is_smart:[46,66],is_snapshot_sourc:[13,66],isadmin:[43,66],isautomaticindexingpolici:[16,66],islock:19,isn:[13,66],isntanc:[13,66],iso8601:[16,31,66],iso:[13,43,66],isol:[13,66],ispubl:[13,66],issu:[5,9,13,28,66],issuer:[16,66],iszoneredund:[16,66],item:[5,13,37,66,67],iter:4,iterations:4,its:[5,13,49,58,66,67],itself:[3,6,7,9,66],j2me:34,j:5,jailbroken:34,jamf:64,jamfcomputergroup:[45,64],java:34,java_hom:8,javascript:67,jdk:8,job:[2,5,9,13,16,19,22,25,28,31,34,37,40,43,49,52,55,58,61,63,64,66],job_titl:[58,66],join:[0,34,43,66],jre:8,json:[4,10,13,27,34,35,38,41,61,63,66],just:[4,5,8,38,65,67],justifi:5,jvm:[1,8],k8:47,k:[40,66],kb_id:[13,66],keep:[5,8,13,16,62,66],kei:[5,11,13,16,20,23,32,34,37,50,53,56,66],kernel:[13,22,31,66],kernel_id:[13,66],kernel_vers:22,key_nam:[13,66],keyerror:5,keyfingerprint:[13,66],keynam:[13,66],keypair:[13,66],keyspac:[16,66],keyvaulturi:[16,66],keyword:5,kill:[13,66],kind:[16,37,43,66],kinda:4,km:[11,13,37,66],kms_data_key_reuse_period_second:[13,66],kms_key_id:[13,66],kms_master_key_id:[13,66],kmsalia:64,kmsgrant:64,kmskei:64,kmskeyarn:[13,66],kmskeyid:[13,66],know:[4,5,67],known:[13,22,37,66],known_a:[13,66],kube:[49,66],kubeconfig:[47,49,66],kubernet:[11,13,36,37,64],kubernetesclust:64,kubernetescontain:64,kubernetesnamespac:64,kubernetespod:64,kubernetessecret:64,kubernetesservic:64,l103:5,l216:5,l228:5,l230:5,l237:5,l2:5,l37:5,l451:5,l91:5,l94:5,l98:5,label:[4,5,9,12,13,34,55,58,64],labor:4,lag:[13,66],lambda:[11,13,66],lancini:67,landlin:34,lang:65,languag:[40,64,66],larg:[4,63],last:[4,13,16,19,22,25,28,31,34,37,40,43,49,52,55,58,61,63,66],last_accessed_d:[13,66],last_association_execution_d:[13,66],last_changed_d:[13,66],last_directory_sync:34,last_login:[34,52,55,66],last_login_tim:[43,66],last_modified_d:28,last_modified_timestamp:[13,66],last_nam:[55,66],last_ping_date_tim:[13,66],last_pw_chang:52,last_rotated_d:[13,66],last_seen:34,last_statu:[13,66],last_successful_association_execution_d:[13,66],last_upd:34,lastbackupd:[16,66],lastmodifi:[13,66],lastmodifiedtim:[16,66],lastnam:34,lastprocessingresult:[13,66],lastreporttim:19,lastupd:[2,13,16,19,22,25,28,31,34,37,40,43,49,52,55,58,61,62,66,67],lastupdatestatu:[13,66],lastupdatestatusreason:[13,66],lastupdatestatusreasoncod:[13,66],lastusedd:[13,66],lastusedregion:[13,66],lastusedservic:[13,66],later:[4,13,37,66],latest:[13,62,66],latest_restorable_tim:[13,66],latest_version_numb:[13,66],latter:5,launch:[11,13,66],launch_typ:[13,66],launchconfigur:64,launchconfigurationnam:[13,66],launchtempl:64,launchtemplateid:[13,66],launchtemplatenam:[13,66],launchtemplatevers:64,launchtim:[13,66],launchtimeunix:[13,66],layer:[11,13,58,66],lead:[55,66],learn:[4,5,6,7,64],leas:[16,66],leasedur:[16,66],leasest:[16,66],leasestatu:[16,66],least:[37,66],leav:[37,63,66],left:[58,66],legaci:[16,34,41,66],legal:[16,66],len:5,length:[13,43,66],less:5,let:[4,63,67],letter:[11,13,66],level:[13,16,35,40,43,49,64,66],libexec:8,librari:[13,40,65,66,67],licens:[13,16,43,66],license_model:[13,66],license_typ:[16,66],licensetyp:[16,66],life:[13,66],lifecycl:[37,49,66],lifecyclest:[37,66],lightweight:5,like:[1,4,5,6,7,8,10,22,63,67],limit:[4,10,13,16,66,67],limit_s:4,line:[1,4,12,13,61,62,66],link:[6,7,13,16,29,43,52,66],linkdirect:5,lint:[1,5],linux:[8,10,13,62,66],list:[4,5,8,12,13,16,25,28,34,35,37,40,41,43,61,63,65,66,67],list_imag:[13,66],listen:[1,13,65,66,67],littl:5,live:[16,66],ll:10,load:[2,11,13,29,38,40,49,64,66,67],load_balancer_ip:[49,66],load_balancing_schem:[37,66],load_emr_clust:5,loadbalanc:[4,49,64,67],loadbalancerv2:[64,67],local:[1,8,13,16,22,34,66],local_ip:22,localhost:[1,5,8,41,67],locat:[3,5,13,16,37,41,61,66],location_typ:[37,66],locationbyiprang:19,locationnam:[16,66],lock:[13,19,31,34,40,61,66],log:[3,13,16,19,34,37,43,52,66,67],log_bucket:[37,66],log_encryption_kms_key_id:[13,66],log_uri:[13,66],loggedonus:19,logger:5,logging_servic:[37,66],logic:[2,5,13,16,66],login:[14,16,29,43,52,55,66],logout:[55,66],longer:5,look:[1,5,10,63,67],lookup:5,lot:[8,67],low:[22,61],lower:[13,66],lowercas:61,lowest:[13,37,66],lun:[16,66],lyft:[0,1,3,5,9,10,55,62,65,66],m1:8,m:[13,66],mac:[8,13,22,34,66],mac_address:[13,22,66],macaddress:19,machin:[1,8,13,15,16,22,34,35,63,66],machine_domain:22,machine_guid:34,made:[13,22,52,66,67],mai:[1,4,5,6,7,8,13,16,31,34,37,66,67],mail:[16,66],mailbox:[43,66],main:[1,13,66],maintain:[40,66],mainten:[13,66],major:22,major_vers:22,make:[1,2,3,4,6,7,8,13,16,29,35,43,61,62,63,66,67],make_target_node_match:5,makeadmin:[43,66],malform:5,manag:[1,2,11,13,34,35,36,37,66],managed_disk_storage_typ:[16,66],mani:[5,10,12,13,16,25,58,64,66],manifest:[13,66],manipul:5,manual:[2,4,6,7,8,13,19,61,66],manufactur:22,map:[0,3,11,13,25,34,37,53,55,64,66],map_customer_owned_ip_on_launch:[13,66],map_public_ip_on_launch:[13,66],marco:67,mariadb:[13,66],mark:[4,13,63,66],master:[13,37,40,52,66],master_authorized_network:[37,66],master_public_dns_nam:[13,66],master_usernam:[13,66],masterarn:[13,66],masterauth_password:[37,66],masterauth_usernam:[37,66],match:[4,5,13,37,53,63,65,66,67],matching_fingerprint:[13,66],maven:61,max:[13,16,52,66],maxageinsecond:[16,66],maximum:[13,16,43,66],maximum_execution_frequ:[13,66],maximum_message_s:[13,66],maximumbatchingwindowinsecond:[13,66],maximumrecordag:[13,66],maximumretryattempt:[13,66],maxinstancelifetim:[13,66],maxintervalinsecond:[16,66],maxreceivecount:[13,66],maxresult:41,maxshar:[16,66],maxsiz:[13,66],maxsizebyt:[16,66],maxstalenessprefix:[16,66],maxthroughput:[16,66],mb:19,md5:[13,66],mean:[4,13,16,22,66],medium:[22,61],member:[4,13,37,40,41,43,55,58,66],member_auto_scale_group:[13,66],member_aws_group:[13,66],member_of_aws_vpc:[13,66],member_of_db_subnet_group:[13,66],member_of_dns_zon:[13,66],member_of_duo_group:34,member_of_ec2_reserv:[13,66],member_of_ec2_security_group:[4,13,66],member_of_gcp_vpc:[37,66],member_of_ip_rul:[4,13,37,66],member_of_okta_group:[55,66],member_of_okta_rol:[55,66],membership:[11,13,66],memori:[13,66],memory_reserv:[13,66],mention:67,menu:67,meraki:34,merg:[4,5,58,63,66],mesh:[13,66],messag:[13,43,63,66],message_retention_period:[13,66],meta_gener:[37,66],metadata:[10,16,37,64],method:[13,16,34,35,37,43,52,66],metric:[13,37,62,66],mfa:[13,52,66],mfa_delet:[13,66],mhz:19,mib:[13,66],micro:63,microsoft:[13,14,66],midnight:[13,66],might:[8,22,63,67],millisecond:5,mind:8,minim:[25,40,66],minimum:[13,38,66],minimumcompressions:[13,66],minor:[13,22,66],minor_vers:22,minsiz:[13,66],minut:[0,43,66],mirror:26,miss:63,mm:[43,66],mobil:[34,52,55,66],mobile_otp:34,mobile_otp_en:34,mobile_phon:[55,66],mobileiron:34,mock:5,mode:[13,16,22,37,55,66],model:[5,13,34,66],moder:[13,66],modif:[16,66],modifi:[5,13,16,40,66],modified_timestamp:22,modifiedd:[13,66],modul:[2,3,4,8,9,11,15,18,21,24,27,30,33,36,39,41,42,47,48,51,52,53,54,57,60,63,66],modulesyncmetadata:64,mongodb:[16,66],monitor:[13,37,63,66],monitoring_en:[13,66],monitoring_role_arn:[13,66],monitoring_servic:[37,66],monitoringst:[13,66],monthli:0,more:[1,4,5,6,7,8,9,10,13,16,29,35,37,43,62,63,64,65,66],most:[5,13,22,62,63,66,67],mount:3,move:[13,66],mpstrength:52,much:5,mulitpl:47,multi:[13,66],multi_az:[13,66],multiattachen:[13,66],multifactor:52,multimast:[13,66],multipl:[13,16,34,38,43,66],multiplewriteloc:[16,66],must:[13,37,43,58,66],mutlipl:47,my:[2,19,37,64,66],my_custom:[41,43,66],mybigfixrelai:19,myproject:[37,66],myrepo:65,mysql:[13,66],n:[4,63,67],name:[4,5,10,12,13,14,16,17,20,22,23,25,31,32,34,37,38,40,41,43,46,49,50,52,53,55,56,58,59,61,63,64,65,66],nameserv:[37,64,67],namespac:[13,48,49,66],narrowest:5,nat:[37,66],nativ:19,nearest:[13,66],neat:4,necessari:[3,5,25,34,66],need:[1,2,3,4,10,13,35,40,41,61,62,66,67],neg:[58,66],neither:3,neo4j:[1,2,3,5,6,7,8,62,63,66,67],neo4j_auth:8,neo4j_password:3,neo4j_path:8,neo4j_sess:5,neo4j_url:1,net:[19,67],network:[4,11,13,16,37,66,67],network_access_polici:[16,66],network_border_group:[13,66],network_interfac:[4,13,37,66],network_interface_id:[13,66],network_mod:[13,66],network_polici:[37,66],network_ti:[37,66],networkinterfac:[4,37,64,67],networkinterfaceid:[13,66],never:[34,52],neverloggedin:52,newinstancesprotectedfromscalein:[13,66],newli:[13,37,66],newurl:67,next:[4,43,66,67],nic_id:[37,66],nist:26,nlb:[13,66],node:[1,2,4,9,12,13,16,19,22,25,28,31,34,37,40,43,49,52,55,58,61,62,64,66],node_typ:[13,66],nodetyp:66,nodetype:66,nodetypea:66,nodetypeb:66,nodetypec:66,non:[37,66],none:[5,8,13,22,28,34,37,52,66],noopen:67,nor:3,normal:[1,13,22,66],notact:[13,66],notat:[37,64,67],note:[2,14,22,23,34,37,47,52,63,64],notic:[4,67],notif:[13,58,66],now:[1,4,5,63,67],npm:61,ns:[13,66],nullabl:[13,66],num_loop:[58,66],number:[4,10,13,16,31,34,37,40,43,50,52,58,66],number_of_nod:[13,66],numer:22,nutshel:4,nvd:61,o:[3,13,41,66],oath:[55,66],oauth2:41,object:[1,5,13,16,17,20,25,26,29,31,32,37,38,40,47,50,53,56,58,66],observ:[58,66],obtain:[13,38,41,66],obviou:5,occur:[4,13,66],off:[8,31,34,64,66],offer:[5,13,16,66],offered_bi:[25,66],offeringclass:[13,66],offeringtyp:[13,66],offici:[8,10,29,35,37,66],ok:[1,5],okta:[5,33,64],okta_api_kei:5,okta_last_upd:[55,66],okta_last_updated_bi:[55,66],oktaadministrationrol:64,oktaadministrationrole:[55,66],oktaappl:64,oktagroup:[53,64],oktaorgan:64,oktatrustedorigin:64,oktaus:64,oktauserfactor:64,old:5,older:[5,8,13,66],omit:5,on_call_handoff_notif:[58,66],onc:[3,63,67],one:[5,6,7,8,10,12,13,16,31,34,37,47,63,66,67],one_to_one_nat:[37,66],ones:5,onli:[1,2,3,4,6,7,8,10,12,13,16,17,34,35,37,38,40,43,58,63,66,67],opaqu:[49,66],open:[4,13,22,41,58,66,67],oper:[4,8,13,16,22,34,40,43,55,63,66,67],oppos:[5,67],optim:[13,66],option:[1,2,8,10,13,16,25,37,40,61,62,66,67],option_group_nam:[13,66],oracl:[13,66],order:[4,35,58,65,66],orderbi:41,org:[38,53],org_unit_path:[43,66],organ:[35,37,38,40,43,47,53,54,55,61,66],organizationview:35,origin:[13,16,34,54,55,58,66],original_snapshot_create_tim:[13,66],originalsnapshotcreatetim:[13,66],os:[8,13,19,22,34,41,66],os_build:[22,34],os_famili:34,os_usernam:34,os_vers:[22,34],oss:0,ostyp:[16,66],other:[2,4,6,7,8,10,13,22,29,34,35,37,38,52,53,61,64,66],other_relationship:5,otherwis:[5,6,7,8,13,34,66,67],our:[0,1,2,5,6,7,8,13,62,63,65,66,67],out:[1,4,6,7,34,62,67],outag:[16,66],outbound:[37,66],outbound_account:[13,66],outpost:[13,66],outpost_arn:[13,66],outpostarn:[13,66],output:[5,10,13,38,41,66,67],outsid:[40,66],outside_collab_:[40,66],outstand:[58,66],over:[4,5,13,63,66],overview:2,overwritten:[37,66],own:[4,5,12,13,40,62,63,66,67],owner:[6,7,13,31,37,40,66],owner_ent:[37,66],owner_entity_id:[37,66],owner_id:[13,66],owner_uuid:[31,66],ownerid:[13,66],ownership:[13,66],owning_servic:[13,66],p:[13,66],packag:[1,64],package_manag:61,packagetyp:[13,66],packet:[37,66],page:[8,23],pagerduti:64,pagerdutyescalationpolici:64,pagerdutyescalationpolicyrul:[58,66],pagerdutyintegr:64,pagerdutyschedul:64,pagerdutyschedulelay:64,pagerdutyservic:64,pagerdutyteam:64,pagerdutyus:64,pagerdutyvendor:[58,66],pai:[37,66],paid:[13,66],pair:[11,13,34,37,66],palm:34,panel:34,parallelizationfactor:[13,66],parallelqueri:[13,66],paramet:[4,12,13,20,34,43,47,50,53,56,66],parent:[9,13,37,43,61,66],parentid:[13,66],part:[1,4,5,13,16,34,37,53,62,66,67],part_of_subnet:[13,37,66],parti:[43,66],partial:[5,37,66],partial_uri:[5,37,66],particular:[5,9,13,66],particularli:[6,7],partner:[16,66],partnerdatabas:[16,66],partnerloc:[16,66],partnerrol:[16,66],partnerserv:[16,66],pass:[3,13,17,20,26,32,47,49,50,53,56,59,66],passcod:34,password:[3,5,13,14,17,34,37,43,52,55,66],password_chang:[55,66],password_reset_requir:52,password_statu:34,passwordlastus:[13,66],pastdu:[16,66],patch:[13,66],patchcompliancedata:[13,66],path:[1,4,6,7,8,13,16,43,47,61,66,67],pathpart:[13,66],pattern:5,paus:[13,66],peer:[11,13,66],peeringconnect:[13,66],pend:[13,16,34,66],pending_count:[13,66],pendingaccept:[13,66],per:[13,35,37,66],percent:[13,66],percent_progress:[13,66],percentag:[13,16,66],percentcomplet:[16,66],perform:[2,4,8,13,16,34,41,61,66,67],performance_insights_en:[13,66],perhap:10,period:[1,13,37,62,66],permalink:64,permiss:[10,13,16,25,34,40,58,64,66],permissions_warn:[25,66],permit:[13,16,66],person:29,perspect:5,phase:[4,49,66],phish:[55,66],phone:[34,55,66],phone_id:34,photo:[43,66],physic:[19,25,37,66],pick:[10,34,67],pid_mod:[13,66],pin:[40,66],ping:[13,66],ping_statu:[13,66],pinned_vers:[40,66],pip:[1,8],pivot:52,place:[13,37,66],placehold:[25,37,63,66],placement_ten:[13,66],plai:8,plain:2,plan:[16,66],plane:[13,66],platform:[6,7,13,22,34,37,61,66],platform_famili:[13,66],platform_id:22,platform_nam:[13,22,66],platform_typ:[13,66],platform_vers:[13,66],pleas:[13,20,35,41,66],plu:[13,43,66],pod:[37,48,49,66],point:[5,13,16,35,66,67],polici:[10,11,13,16,25,35,37,57,58,64,66],policy_id:[13,66],policy_nam:[13,66],policy_stat:[13,66],policy_vers:[13,66],policynam:[13,66],policyunivers:[13,66,67],pool:[13,16,66],pop:63,popul:[14,17,20,23,29,32,38,41,50,53,56,59],port:[1,13,37,62,65,66,67],port_rang:[37,66],portion:[49,58,66],posit:[13,66],possibl:[3,5,64],post:[0,58,66],postdelai:34,postgresql:[13,66],power:[4,6,7],pphone:34,pr:5,practic:5,pre:1,precis:5,predefin:[13,66,67],predelai:34,predetermin:[37,66],prefer:[5,8,58,66],preferred_backup_window:[13,66],preferred_maintenance_window:[13,66],prefix:[13,62,66],preflight:[16,66],premier:34,premis:[13,19,66],premium:[37,66],prepar:[17,20,23,29,32,35,38,50,53,56],prepend:[40,66],present:[5,6,7,12,13,34,37,40,66],preserv:4,prevent:[13,31,66],previou:[4,14,23,29,38,41],previous:5,price:[13,25,66],pricip:12,primari:[13,16,40,43,58,66],primary_cidr_block:[13,66],primary_email:[43,66],primary_region:[13,66],primaryemail:[41,43,66],primarylanguag:[40,66],primaryloc:[16,66],princip:[10,11,12,13,14,16,66,67],principl:2,print:41,print_funct:41,prioriti:[16,37,66],privaci:[25,66],privacy_polici:[25,66],privat:[13,16,20,37,40,66],private_dns_nam:[13,66],private_endpoint:[37,66],private_endpoint_en:[37,66],private_ip:[37,66],private_ip_address:[13,31,66],private_ip_google_access:[37,66],private_nod:[37,66],privateendpointid:[16,66],privateipaddress:[13,63,66],privatezon:[13,66],privileg:[13,28,43,66],privileges_requir:28,probabl:8,probe:[49,66],problem:5,problem_typ:28,procedur:1,process:[4,5,8,13,62,66],processor_featur:[13,66],prod:[13,37,66],product:[8,13,22,62,66],product_typ:22,product_type_desc:22,productdescript:[13,66],profil:[8,10,13,40,43,66],prog:1,program:[40,66],programminglanguag:[64,65],progress:[13,66],project:[0,30,31,37,40,41,61,66],project_id:[31,37,41,66],project_nam:[37,66],projectid:[37,66],projectnumb:[37,66],promot:[13,66],prompt:[10,34,41],propag:[13,66],propagate_tag:[13,66],proper:[13,66],properli:[4,5],properti:[2,8,13,34,37,43,55,63,64,66],propertyref:5,protect:[13,66],protip:64,protocol:[13,16,37,66],provhash:50,provid:[5,13,22,23,25,35,37,40,41,43,52,53,55,58,62,66],providernam:19,provis:[13,22,66],provision_statu:22,provisioningst:[16,66],proxi:[13,66],proxy_configuration_container_nam:[13,66],proxy_configuration_typ:[13,66],pseudo_termin:[13,66],ptr:[37,66],public_endpoint:[37,66],public_ip:[13,37,66],public_ipv4_pool:[13,66],public_ptr_domain_nam:[37,66],publicaccess:[16,66],publicdnsnam:[13,63,65,66,67],publicipaddress:[13,66],publicli:[13,16,40,66],publicly_access:[13,66],publicnetworkaccess:[16,66],publish:28,published_d:28,pull:[8,10,13,35,62,66],pull_started_at:[13,66],pull_stopped_at:[13,66],purchas:[13,66],purpos:[43,66],push:34,push_en:34,put:4,py:[1,5,9,66],pypi:61,pytest:1,python:[1,4,5,6,7,8,38,40,41,65,66,67],pythonlibrari:[64,65],q:5,qualifi:[13,16,66],queri:[2,4,12,13,53,61,63,64,66,67],query_directori:63,querybuild:5,queryselectoral:67,queue:[11,13,16,66],quick:64,quickest:63,quickli:[63,67],quickstart:41,quota:[13,66],r:[1,5,13,65,66,67],racecar:66,rai:[13,66],rais:5,ram:[13,19,66],ramdisk_id:[13,66],ran:62,rang:[13,37,66,67],rare:[16,66],rate:[10,25,66],rather:[3,6,7,43,66],rating_us:[25,66],rbac:14,rd:[5,11,13,64,66],rdscluster:64,rdsinstanc:[64,65,67],rdssnapshot:64,re:[0,1,8,13,66,67],reach:[13,58,66],reachability_check:61,reachability_condit:61,reachabl:61,read:[4,5,10,11,12,13,16,17,29,35,38,40,43,63,66,67],read_acp:[13,66],read_only_limited_us:[58,66],read_only_us:[58,66],readabl:[13,31,66],reader:[13,14,66],reader_endpoint:[13,66],readi:[49,62,66],readonli:41,readonly_root_filesystem:[13,66],real:34,realnam:34,reason:[13,66],rebalanc:[13,66],recap:2,receiv:[5,13,37,66],receive_message_wait_time_second:[13,66],receivecount:[13,66],receivemessag:[13,66],recent:[13,22,62,63,66,67],recommend:[4,5,37,62,65,66],reconnect:[13,66],record:[0,4,11,13,16,22,37,62,66],recording_group_all_support:[13,66],recording_group_include_global_resource_typ:[13,66],recording_group_resource_typ:[13,66],recov:[13,66],recover:[16,66],recoverabledbid:[16,66],recoveri:[13,55,66],recoverywindowindai:[13,66],red:[6,7],redirect:[13,66],redirect_uri:41,redrive_policy_dead_letter_target_arn:[13,66],redrive_policy_max_receive_count:[13,66],redshift:[11,13,66],redshiftclust:64,reduc:22,reduced_functionality_mod:22,redund:[16,66],reenabl:3,ref:[40,66],ref_url:61,refer:[5,13,28,37,38,40,41,43,61,63,66,67],referenc:[13,66],refresh_token:41,regardless:[6,7],regex:53,region:[5,10,13,16,31,37,66],regist:[13,34,66],registered_at:[13,66],registered_bi:[13,66],registr:[13,34,66],registration_d:[13,66],registri:[13,62,66],reject:[13,16,66],rel_label:5,relabel:67,relai:19,relat:[10,13,43,66,67],relationship:[2,4,6,7,10,11,12,45,62,64,67],relationship_nam:12,relationship_r:66,relationshipnam:12,releas:[13,34,62,66],release_label:[13,66],relev:8,relproperti:5,remain:[13,16,66],remainingretentiondai:[16,66],remedi:[4,22],remediation_id:22,remot:19,remotedesktopisen:19,remov:[4,5,41,63],reopen:22,repeat:[58,66],replac:67,replaceal:67,repli:[54,64],replic:[16,66],replica:[11,13,16,66],replicationrol:[16,66],replicationst:[16,66],replyuri:[55,66],repo:[13,29,38,39,40,64,66],repo_imag:[13,66],repo_upgrade_on_boot:[13,66],report:[6,7,19,25,65,66],report_link:[25,66],repositori:[13,40,61,64,66],repres:[5,9,13,16,19,31,34,37,43,61,66],represent:[5,13,16,22,25,28,31,37,40,46,49,52,55,58,66,67],req:65,request:[13,16,37,43,52,56,58,66],requested_ami_vers:[13,66],requester_cidr:[13,66],requester_id:[13,66],requester_manag:[13,66],requester_pai:[37,66],requester_region:[13,66],requester_vpc:[13,66],requesterid:[13,66],requir:[1,2,8,13,16,23,28,38,40,43,61,65,66],requires_compat:[13,66],resel:[43,66],reserv:[11,13,66],reservationid:[13,66],reset:[3,52],resid:[13,37,66],resiz:[13,66],resold:[43,66],resolut:[16,66],resolv:[5,13,37,58,66,67],resourc:[5,10,11,12,13,16,19,31,34,35,36,37,40,43,55,61,65,66,67],resource_typ:[13,66],resourcegroup:[16,66],resourcemanag:35,resourcerecordset:[13,37,66],resourcetyp:12,respons:[5,16,34,66],rest:[11,13,66],restor:[13,16,66],restorabledroppeddbid:[16,66],restored:[16,66],restorepointtyp:[16,66],restrict:[13,66],restrict_public_bucket:[13,66,67],restricted_access:[58,66],result:[2,4,10,13,38,41,63,66,67],retain:[13,37,66],retent:[16,66],retention_period:[37,66],retentiondai:[16,66],retirej:[25,66],retri:[5,10,13,66],retriev:[5,13,34,43,66],reus:[13,66],revis:[13,66],revisionid:[13,66],rfc:[37,66],rfm:22,right:4,rim:34,risk:[6,7,25,64,65],risk_csp_scor:[25,66],risk_extcalls_scor:[25,66],risk_metadata:[25,66],risk_optional_permissions_scor:[25,66],risk_permissions_scor:[25,66],risk_tot:[25,65,66],risk_vuln_scor:[25,66],risk_webstore_scor:[25,66],riski:64,rm:62,road:0,role:[10,11,13,14,16,35,40,43,53,54,55,58,66],role_arn:[10,13,66],rolearn:[13,66],roleid:[13,66],roll:[13,66],rollingback:[13,66],root:[10,13,34,66],rootdevicenam:[13,66],rootdevicetyp:[13,66],rotat:[13,66],rotatesecret:[13,66],rotation_en:[13,66],rotation_lambda_arn:[13,66],rotation_rules_automatically_after_dai:[13,66],rotation_turn_length_second:[58,66],rotation_virtual_start:[58,66],round:[13,66],rout:[13,37,66],route53:[11,13,66],router:[37,66],routing_confg_routing_mod:[37,66],row:67,rpr:12,rule:[4,11,13,16,37,43,61,66,67],rule_id:[13,61,66],rule_typ:[13,37,66],ruleid:[13,37,66],run:[2,3,8,10,13,35,49,61,62,64,66,67],runinst:[13,66],running_ami_vers:[13,66],running_count:[13,66],runtim:[13,23,66],runtime_id:[13,66],runtime_platform_cpu_architectur:[13,66],runtime_platform_operating_system_famili:[13,66],s3:[11,12,13,64,66],s3_bucket_nam:[13,66],s3_key_prefix:[13,66],s3_kms_key_arn:[13,66],s3acl:[64,67],s3bucket:[9,12,64,65,67],s3policystat:64,s:[1,2,3,6,7,8,9,10,13,20,22,25,31,34,35,37,40,41,43,49,53,58,61,62,63,65,66,67],sai:[4,37,63,66,67],sake:5,sam:[55,66],sam_account_nam:[55,66],same:[4,5,13,31,37,43,66],saml:53,sampl:[38,64,67],save:[1,63],sca:[60,61],scalar:4,scale:[13,16,66],scale_down_behavior:[13,66],scaling_configuration_info_auto_paus:[13,66],scaling_configuration_info_max_capac:[13,66],scaling_configuration_info_min_capac:[13,66],scan:[13,66],scan_tim:61,scenario:[6,7,10],schedul:[13,57,58,62,66],schedule_id:[58,66],schema:[2,45,64,67],scheme:[13,66,67],scope:[13,16,28,29,38,41,55,59,66],scope_compliance_resource_typ:[13,66],scope_tag_compliance_resource_id:[13,66],scope_tag_kei:[13,66],scope_tag_valu:[13,66],score:[22,25,28,52,64,66],screen:34,screenlock:34,script:[1,3,41,62],scroll:[37,66],sda1:[13,66],sdk:[41,43,66],search:[13,66],searchparam:67,second:[13,16,34,37,38,43,58,63,66],second_email:[55,66],secondari:[11,16,55,66],secondaryloc:[16,66],secret:[11,13,14,20,23,32,41,48,49,50,59,66],secretbinari:[13,66],secretsmanagersecret:64,secretstr:[13,66],section:[1,4,5,8,12,29],secur:[1,4,5,6,7,8,10,11,13,23,34,37,52,61,66,67],security_ag:34,security_configur:[5,13,66],security_group:[13,66],security_group_id:[13,66],securityaudit:10,securitycommonsens:35,securityconfigur:5,securitygroup:[13,66],securityhub:64,securityreview:35,securityupd:[13,66],see:[0,1,3,4,5,8,9,10,13,20,34,35,37,43,62,63,66,67],seed:[16,66],seen:[5,13,22,66],select:[34,43,66,67],self:20,self_link:[37,66],selinux:[13,66],semgr:61,semgrep_app_token:59,semicolon:[16,66],send:[13,43,55,62,66],sens:5,sensit:35,sensor:22,sent:[16,34,58,62,66],separ:[8,13,16,66],serial:[34,41],serv:[13,37,49,66],server:[8,10,13,16,19,37,58,62,66,67],serverless:[13,66],serves_pod:[49,66],servic:[4,6,7,10,13,14,16,22,34,35,37,41,43,48,49,57,58,66],service_provid:22,service_provider_account_id:22,servicelevelobject:[16,66],servicerol:[13,66],services_ipv4cidr:[37,66],session:5,set:[3,4,5,6,7,8,10,13,14,16,22,29,31,34,35,37,43,56,58,62,63,66,67],set_in_kwarg:5,set_public_ptr:[37,66],setprivateipgoogleaccess:[37,66],setpublicptr:[37,66],settings_container_insight:[13,66],setup:[1,5,40,64,66],setup_requir:[40,66],sever:[13,22,28,61,66],sf:19,sg:[13,66],sha256:[13,66],sha:[13,49,66],shape:5,shard:[13,66],share:[1,13,16,43,66],shared_with:[13,66],sharequota:[16,66],shareusagebyt:[16,66],shield:[37,66],shielded_nod:[37,66],shift:[58,66],short_descript:[25,66],shortcut:[4,37,64,66],shorten:66,should:[1,3,4,5,8,9,10,12,13,16,23,37,43,63,66],show:[10,13,58,63,66,67],shown:[4,13,38,63,66],shutdown:[13,66],sid:[13,66],sign:[13,43,66],sign_on_mod:[55,66],signatur:22,signifi:[37,66],signingjobarn:[13,66],signingprofileversionarn:[13,66],signon:[55,66],similar:[4,13,66,67],simpl:[49,66],simpli:[37,63,66,67],sinc:[5,13,66],singl:[4,5,13,25,40,47,52,66],site:[25,40,52,66],size:[13,16,25,31,66,67],skeleton:2,sketch:4,skip:4,sku:[16,66],slack:0,slash:[13,43,66],slightli:63,slow:8,slug:[31,40,61,66],sm:34,small:67,smart:[46,66],smartphon:34,sms_enabl:34,sms_passcodes_s:34,sn:[13,66],snapshot:[11,13,16,62,66],snapshot_create_tim:[13,66],snapshot_database_tim:[13,66],snapshot_target:[13,66],snapshot_typ:[13,66],snapshotdatabasetim:[13,66],snapshotid:[13,66],sns_topic_arn:[13,66],so:[1,3,4,5,6,7,8,10,20,37,40,66,67],soft:[13,16,66],softwar:[13,37,40,61,66],some:[5,9,12,13,63,66,67],somefield:5,someth:[5,10],sometim:5,soon:[46,66],sopho:34,sourc:[2,4,5,8,9,11,13,16,34,66,67],source_db_snapshot_identifi:[13,66],source_dest_check:[13,66],source_detail:[13,66],source_id:[13,66],source_identifi:[13,66],source_own:[13,66],source_region:[13,66],source_security_group:[13,66],source_typ:[13,66],sourceid:[13,66],sourcetyp:[13,66],sp:14,span:67,speak:34,spec:[13,66],specif:[1,5,8,12,13,16,37,66,67],specifi:[5,8,12,13,16,29,31,34,37,38,40,47,49,53,62,63,65,66,67],specificnod:66,split:[13,66],spoke:10,spot:[13,66],spot_pric:[13,66],spotlight:[21,22],spread:[16,66],sq:[11,13,66],sql:[13,15,16,66,67],sqsqueue:64,sse:[13,66],ssh:[11,40,66],ssh_login_to:[13,66],sshurl:[40,66],ssl:[13,66],ssl_polici:[13,66],ssm:[13,66],ssminstanceinform:64,ssminstancepatch:64,sstzd:[43,66],st:[10,11],stabl:[13,66],stack:[3,65],stage:[1,2,11,13,66],stale:[4,5,16,62,66],stamp:[13,66],standard:[1,13,37,53,66],start:[1,2,3,13,16,37,41,58,61,62,63,66],start_aws_ingest:1,start_col:61,start_lin:61,start_timeout:[13,66],started_at:[13,66],started_bi:[13,66],startedbi:[13,66],startingposit:[13,66],startingpositiontimestamp:[13,66],starttim:[13,16,66],startup:[49,66],state:[13,16,31,37,49,55,58,63,66],statement:[4,10,13,66,67],statemessag:[13,66],statereason:[13,66],statereasoncod:[13,66],statu:[13,16,22,31,34,37,55,58,66],status_chang:[55,66],status_cod:[13,66],status_image_id:[49,66],status_image_sha:[49,66],status_messag:[13,66],status_phas:[49,66],status_readi:[49,66],status_reason:[13,66],status_start:[49,66],statusofprimari:[16,66],statusofsecondari:[16,66],statys_st:[49,66],stdin:[13,66],step:[1,4,5,10,13,14,17,20,23,26,29,32,35,38,41,43,47,50,53,56,59,66,67],still:[5,13,66],stillfak:38,stop:[13,66],stop_cod:[13,66],stop_timeout:[13,66],stopped_at:[13,66],stopped_reason:[13,66],stopping_at:[13,66],storag:[13,15,16,31,36,37,66],storage_class:[37,66],storage_encrypt:[13,65,66,67],storage_throughput:[13,66],storage_typ:[13,66],storageclass:[37,66],storageencrypt:[13,66],storageendpoint:[16,66],store:[12,13,16,23,52,66,67],stori:[6,7],str:5,stream:[13,66],strenght:52,string:[5,12,13,16,19,31,34,37,40,43,58,61,66],structur:[4,5,38,63],sts_assume_role_allow:[13,66],sts_assumerole_allow:[13,66],style:67,sub:[5,9,66],sub_resource_relationship:5,subject:[43,66],submit:5,subnet:[4,11,13,16,37,66,67],subnet_arn:[13,66],subnetaddress:19,subnetid:[13,66],subnetwork:[37,66],subscribed_at:[13,66],subscript:[14,16,66],subzon:[13,66],successfulli:[5,13,63,66],succinct:[58,66],suffici:34,suit:[1,25,41,43,66],suitabl:[58,66],sum:[25,66],summar:61,summari:[25,49,58,61,66,67],superced:[37,66],suppli:[2,13,61,66],support:[2,8,11,13,22,25,34,37,38,41,43,58,63,66],support_hours_days_of_week:[58,66],support_hours_end_tim:[58,66],support_hours_start_tim:[58,66],support_hours_time_zon:[58,66],support_hours_typ:[58,66],support_sit:[25,66],supportshttpstrafficonli:[16,66],suppos:67,sure:[5,8,29,61,67],surnam:34,suspend:[43,66],sy:[1,37,66],symbian:34,sync:[2,3,4,8,9,10,13,14,16,19,22,25,28,31,34,37,40,43,47,49,52,55,58,61,66,67],sync_:1,synced_typ:[9,66],syncedtyp:[9,66],syncmetadata:64,syntax:[2,66],system:[13,16,22,34,49,66],system_manufactur:22,system_product_nam:22,t2:63,t:[1,3,4,5,10,13,37,43,66,67],tab:67,tabl:[11,12,13,16,66,67],tablenam:[16,66],tag:[1,5,11,16,22,31,37,64],tag_id:[37,66],tagkei:[13,66],tagvalu:[13,66],take:[1,4,8,37,38,66],taken:[13,16,66],talk:0,tamper:34,target:[13,37,66],target_label:12,target_node_label:5,target_node_match:5,target_tag:[37,66],targetgroup:67,targetgrouparn:[13,66],targetkeyid:[13,66],targetnodematch:5,task:[13,62,66],task_arn:[13,66],task_definit:[13,66],task_definition_arn:[13,66],task_role_arn:[13,66],tcp:[13,37,66],tcp_udp:[13,66],tde:[13,66],tde_credential_arn:[13,66],team:[40,57,58,66],teamer:[6,7],tell:[4,5],templat:[11,13,63,66],temporarili:3,tenanc:[13,66],tenant:[13,14,16,66],term:[41,43,66],termin:[1,13,16,49,66],termination_protect:[13,66],terminationallow:[16,66],test:[2,8,41],test_iam:1,test_integr:1,test_lint:1,test_load_group:1,test_unit:1,testabl:1,text:[40,66],tgw:[13,66],tgw_id:[13,66],than:[3,5,6,7,8,10,13,43,53,66],thei:[5,6,7,12,13,53,66],them:[4,5,6,7,10,13,37,65,66,67],therefor:[5,13,66],thi:[1,3,4,5,8,9,10,12,13,14,16,19,22,23,25,28,31,34,35,37,40,41,43,49,52,55,58,61,62,63,65,66,67],thing:[4,10,13,66,67],third:[43,66],those:[5,10,13,32,66],though:[5,13,58,66],thread:[13,66],threat:[16,66],throttl:10,through:[3,4,5,6,7,37,63,66,67],throughout:35,throughput:[13,16,66],thu:[13,66],thumbnail_photo_etag:[43,66],thumbnail_photo_url:[43,66],tier:[16,37,66],time:[1,4,5,8,13,16,19,22,25,28,31,34,37,40,43,49,52,55,58,61,62,63,66,67],time_cr:[37,66],time_zon:[58,66],timeout:[13,56,66],timestamp:[5,13,16,19,22,25,28,31,34,37,40,43,49,52,55,58,61,62,63,66],timezon:[13,66],tip:[8,62],titl:[13,58,61,66],tl:[13,66],to_json:41,to_port:[13,66],todo:3,togeth:[4,13,40,66],token:[29,34,38,41,53,56,59],token_id:34,token_uri:41,toler:[16,66],too:[4,5],tool:[6,7,13,65,66],toomanyrequestexcept:10,top:[43,65,66,67],topic:[13,66],toport:[13,37,66],total:[13,31,66],totalcomplet:4,totallyfak:64,totalscor:52,totp_step:34,touch:34,toward:5,trace:[5,13,66],tracingconfigmod:[13,66],tracingen:[13,66],track:[19,40,64,66],traffic:[4,13,16,37,66],trail:[13,66],transact:[13,66],transfer:[13,66],transform:2,transit:[13,16,55,61,66],transition_to_statu:[55,66],translat:2,transpar:[16,66],travers:5,tree:4,triag:[40,66],trigger:[13,58,61,66],trivial:5,truncat:[13,66],trust:[10,11,13,54,55,66],trusted_endpoint:34,trusts_aws_princip:[13,66],ttl:[16,37,66],tty:[13,66],tumblingwindowinsecond:[13,66],turn:[8,64],tutori:[4,64],two:[5,13,63,66],tx:5,txt:[1,40,61,66],type:[1,4,5,9,13,16,22,25,34,37,43,49,55,58,63,66,67],typehint:5,typic:[40,66],u2f:34,u2f_token:34,u:[41,65],udp:[13,66],ui:3,uid:[49,66],ultra_ssd_en:[16,66],unavail:[13,16,66],unavoid:5,undelet:[43,66],under:[13,16,40,66],understand:[4,5,6,7,35],unencrypt:[34,64],unencryptedinst:[65,67],unhealthi:[13,66],uniform:[13,66],uniqu:[5,13,16,22,31,34,37,40,43,61,66],unit:[1,5,13,16,61,66],univers:[13,31,34,66],unix:[5,13,34,62,63,66],unix_timestamp_1:63,unix_timestamp_2:63,unknown:[22,34],unless:[13,66,67],unlock:34,unnecessari:1,unproven:22,unset:[34,58,66],unspecifi:[37,66],until:[13,25,66],unus:[13,66],unwind:5,up:[2,3,5,8,10,13,14,16,29,34,63,66,67],updat:[1,2,5,13,16,19,22,25,28,31,34,37,40,43,49,52,55,58,61,66],update_tag:[2,62],updated_at:[31,66],updated_timestamp:22,updatedat:[40,66],upgrad:[13,66],upload:[13,66],upn:34,upper:[13,66],urgenc:[58,66],uri:[1,3,5,8,13,16,37,43,54,63,64],url:[20,23,25,26,28,37,38,40,41,43,53,58,61,66,67],urlsearchparam:67,us:[0,1,2,4,5,6,7,8,9,10,13,14,16,20,23,31,34,35,37,38,40,43,49,52,53,55,58,61,62,64,66,67],usag:[2,43,61,64,66],usage_at:61,usageoper:[13,66],used_bi:[16,66],user:[3,5,10,11,13,16,23,24,25,28,31,33,34,35,38,39,40,41,42,43,51,52,54,55,57,58,64,66,67],user_id:[34,43,66],user_interact:28,user_upload:[13,66],userid:[13,66],userkei:[43,66],usernam:[13,17,19,34,37,40,43,66],usernma:[55,66],userprofil:10,userreadonli:41,useserverdefault:[16,66],usr:8,usual:[1,5,8,55,66],utc:[13,16,22,61,66],utf:41,util:[9,41,66],uuid:[31,66],v1:[11,23,37,41,43,66],v2:[11,13,66],v4:[27,31,66],v6:[31,66],valid:[2,6,7,13,37,55,66],validation_queri:63,valu:[5,13,14,16,19,22,23,31,34,37,43,58,59,66],variabl:[1,3,5,8,10,13,14,17,20,23,29,32,35,38,41,50,53,56,59,66,67],variou:[40,66],vault:[16,66],ve:[4,5,8,13,66],vector:[6,7,28],vector_str:28,vendor:57,verb:[16,66],veri:[5,8],verif:[34,43,66],version:[8,10,13,16,19,20,22,25,34,37,40,61,62,65,66],version_descript:[13,66],version_info_agent_docker_vers:[13,66],version_info_agent_hash:[13,66],version_info_agent_vers:[13,66],version_numb:[13,66],versioning_en:[37,66],versioning_statu:[13,66,67],versu:2,vhd:[16,66],via:[1,3,4,5,8,13,16,20,34,37,40,41,43,50,53,56,62,66],video:0,view:[5,6,7,8,13,40,63,64,66],viewabl:34,virtual:[13,15,16,19,37,66],virtualenv:1,virtualizationtyp:[13,66],virtualmachin:64,virtualnetworkfilteren:[16,66],virutalenvwrapp:1,visibility_timeout:[13,66],visibl:[13,37,40,43,66],visible_to_all_us:[13,66],visit:29,vm:[13,37,66],vmware:19,vnet:[16,66],voice_en:34,volum:[3,11,13,31,66],volumeid:[13,66],volumes:[13,66],vpc:[5,11,13,37,66],vpc_id:[13,66],vpc_identifi:[13,66],vpc_partial_uri:[37,66],vpcid:[13,66],vpcpeeringconnect:[13,66],vpcpeeringconnectionid:[13,66],vpn:[13,66],vulner:[13,21,22,25,61,66],w:[41,53],wa:[5,13,16,19,22,25,28,31,34,37,40,43,49,52,55,58,61,63,66],wai:[2,4,10,13,61,63,66,67],wait:[13,34,49,66],want:[1,4,5,8,10,13,38,63,65,66,67],warn:[16,25,66],wasn:[13,66],wavelength:[13,66],we:[0,1,4,5,8,9,10,13,37,62,63,66,67],web:[6,7,13,34,40,59,66,67],webacl:[13,66],webaclarn:[13,66],webauthn:34,webauthncredenti:34,webauthnkei:34,webo:34,websit:[25,40,66],webstor:[25,66],weekli:[13,66],well:[37,66],went:[13,66],were:[5,13,63,66],west:10,what:[0,4,5,12,25,64,66],whatev:[4,63],when:[5,10,13,16,19,22,23,25,28,31,34,37,40,43,49,52,55,58,61,62,63,66,67],whenev:[13,37,66],where:[1,4,5,13,16,22,31,37,49,50,61,63,65,66,67],whether:[13,16,19,31,34,37,40,46,49,58,61,66,67],which:[1,2,3,5,12,13,16,34,37,49,58,62,63,64,66],white:[43,66],who:[25,43,55,66],whole:[37,66],why:[5,13,66],wide:[37,41,66],wildcard:[13,66],win2019:19,window:[8,10,13,34,55,62,66,67],windows_domain_qualified_nam:[55,66],wish:[26,53],within:[4,13,16,35,37,40,66],without:[4,5,8,13,37,63,66,67],word:66,work:[0,5,8,13,61,62,66],workflow:[16,66],working_directori:[13,66],workload:[13,66],workspac:[34,41],worri:5,would:[1,12,13,38,66,67],write:[2,4,9,13,16,37,40,63,66,67],write_accelerator_en:[16,66],write_acp:[13,66],writeacceler:[16,66],written:[5,16,66],www:[37,41,66],x:[8,13,61,66],xeon:19,xxxxx:41,y:67,yaml:12,ye:[1,34],yet:[6,7,8,10,34,63],yield:[13,66],you:[1,3,4,5,6,7,8,10,12,13,20,26,29,35,37,38,41,43,50,53,56,61,62,63,65,66,67],your:[1,2,4,6,7,8,10,12,13,20,23,29,35,38,41,43,50,53,56,63,64,66],your_env_var_her:[29,38,41],your_neo4j_instance_bolt_url:1,your_neo4j_instance_port:1,your_neo4j_uri:63,yyyi:[43,66],zero:[13,66],zone:[11,13,16,37,58,66],zone_nam:[37,66],zoneid:[13,66],zoneredund:[16,66]},titles:["Contact","Cartography Developer Guide","<no title>","Testing with docker","How to extend Cartography with Analysis Jobs","How to write a new intel module","What is Cartography?","What is Cartography?","Cartography Installation","Cartography metadata schema","AWS Configuration","Amazon Web Services (AWS)","Permissions Mapping","AWS Schema","Azure Configuration","Microsoft Azure","Azure Schema","BigFix Configuration","Lastpass","BigFix Schema","Crowdstrike Configuration","Crowdstrike","Crowdstrike Schema","Crxcavator Configuration","Duo CRXcavator","Crxcavtor Schema","CVE Configuration","CVE","CVE Schema","Configuration","DigitalOcean","DigitalOcean Schema","Duo Configuration","Duo","Duo Schema","GCP Configuration","Google Cloud Compute (GCP)","GCP Schema","Github Configuration","Github","Github Schema","GSuite Configuration","Google GSuite","GSuite Schema","<no title>","Jamf","Jamf Schema","Kubernetes Configuration","Kubernetes","Kubernetes Schema","Lastpass Configuration","Lastpass","Lastpass Schema","Okta Configuration","Okta","Okta Schema","Pagerduty Configuration","PagerDuty","Pagerduty Schema","Semgrep Configuration","Semgrep","Semgrep Schema","Cartography operations guide","How to use Drift-Detection","<no title>","Sample queries","Cartography Schema","Usage Tutorial"],titleterms:{"2":41,"\u2139":[66,67],"do":[65,67],"import":5,"new":[1,5],A:63,The:[4,5],access:[4,65,67],account:[10,65,67],accountaccesskei:[13,66],across:65,addit:5,all:[5,65,67],amazon:11,an:[4,5],analysi:[4,67],ani:[4,65,67],anonym:[65,67],apigatewayclientcertif:[13,66],apigatewayresourc:[13,66],apigatewayrestapi:[13,66],apigatewaystag:[13,66],applic:65,ar:[65,67],arg:5,argument:5,autom:1,autoscalinggroup:[13,66],aw:[10,11,13,65,66,67],awsaccount:[13,66],awscidrblock:[13,66],awsconfigdeliverychannel:[13,66],awsconfigrul:[13,66],awsconfigurationrecord:[13,66],awsdnsrecord:[13,66],awsdnszon:[13,66],awsgroup:[13,66],awsinspectorfind:[13,66],awsinspectorpackag:[13,66],awsinternetgatewai:[13,66],awsipv4cidrblock:[13,66],awsipv6cidrblock:[13,66],awslambda:[13,66],awslambdaeventsourcemap:[13,66],awslambdafunctionalia:[13,66],awslambdalay:[13,66],awspeeringconnect:[13,66],awspolici:[13,66],awspolicystat:[13,66],awsprincip:[13,66],awsrol:[13,66],awstag:[13,66],awstransitgatewai:[13,66],awstransitgatewayattach:[13,66],awsus:[13,66],awsvpc:[13,66],azur:[14,15,16,66],azurecdbprivateendpointconnect:[16,66],azurecosmosdbaccount:[16,66],azurecosmosdbaccountfailoverpolici:[16,66],azurecosmosdbcassandrakeyspac:[16,66],azurecosmosdbcassandrat:[16,66],azurecosmosdbcorspolici:[16,66],azurecosmosdbloc:[16,66],azurecosmosdbmongodbcollect:[16,66],azurecosmosdbmongodbdatabas:[16,66],azurecosmosdbsqlcontain:[16,66],azurecosmosdbsqldatabas:[16,66],azurecosmosdbtableresourc:[16,66],azurecosmosdbvirtualnetworkrul:[16,66],azuredatabasethreatdetectionpolici:[16,66],azuredatadisk:[16,66],azuredisk:[16,66],azureelasticpool:[16,66],azurefailovergroup:[16,66],azureprincip:[16,66],azurerecoverabledatabas:[16,66],azurereplicationlink:[16,66],azurerestorabledroppeddatabas:[16,66],azurerestorepoint:[16,66],azureserveradadministr:[16,66],azureserverdnsalia:[16,66],azuresnapshot:[16,66],azuresqldatabas:[16,66],azuresqlserv:[16,66],azurestorageaccount:[16,66],azurestorageblobcontain:[16,66],azurestorageblobservic:[16,66],azurestoragefileservic:[16,66],azurestoragefileshar:[16,66],azurestoragequeu:[16,66],azurestoragequeueservic:[16,66],azurestoraget:[16,66],azurestoragetableservic:[16,66],azuresubscript:[16,66],azureten:[16,66],azuretransparentdataencrypt:[16,66],balanc:65,base:65,befor:5,best:5,bigfix:[17,19],bigfixcomput:19,bookmarklet:67,bucket:[65,67],can:67,cartographi:[1,4,5,6,7,8,9,62,66,67],chrome:65,chromeextens:[25,66],clean:4,cleanup:[5,62],cloud:36,command:1,commandlin:5,commun:0,compos:3,comput:36,concept:5,configur:[3,5,10,14,17,20,23,26,29,32,35,38,41,47,50,53,56,59],connect:67,contact:0,credenti:5,crowdstrik:[20,21,22],crowdstrikefind:22,crowdstrikehost:22,crxcavat:[23,24,65],crxcavtor:[25,66],custom:[1,67],cve:[13,22,26,27,28,66],cypher:[4,5],data:67,date:62,dbsubnetgroup:[13,66],defin:[5,67],depend:[40,65,66],detect:63,develop:1,diff:63,digitalocean:[30,31,66],directli:[65,67],dnsrecord:[13,66],dnszone:[13,66],doaccount:[31,66],docker:[3,62],dodroplet:[31,66],doproject:[31,66],drift:63,duo:[24,32,33,34],duoapihost:34,duoendpoint:34,duogroup:34,duophon:34,duotoken:34,duouser:34,duowebauthncredenti:34,dynamodbt:[13,66],ebssnapshot:[13,66],ebsvolum:[13,66],ec2:[4,63,65,67],ec2imag:[13,66],ec2inst:[13,66],ec2keypair:[13,66],ec2privateip:[13,66],ec2reserv:[13,66],ec2reservedinst:[13,66],ec2securitygroup:[13,66],ec2subnet:[13,66],ecrimag:[13,66],ecrrepositori:[13,66],ecrrepositoryimag:[13,66],ecrscanfind:[13,66],ecsclust:[13,66],ecscontain:[13,66],ecscontainerdefinit:[13,66],ecscontainerinst:[13,66],ecsservic:[13,66],ecstask:[13,66],ecstaskdefinit:[13,66],eksclust:[13,66],elasticipaddress:[13,66],elb:65,elblisten:[13,66],elbv2:65,elbv2listen:[13,66],emrclust:[13,66],encrypt:[65,67],endpoint:[13,66],english:4,enrich:67,error:5,esdomain:[13,66],exampl:[3,4,63],expos:[63,65,67],extend:[4,67],extens:65,fast:5,field:5,file:[12,63],filenam:63,first:4,firstseen:5,frequenc:62,from:1,gcp:[35,36,37,66],gcpbucket:[37,66],gcpbucketlabel:[37,66],gcpdnszone:[37,66],gcpfirewal:[37,66],gcpfolder:[37,66],gcpforwardingrul:[37,66],gcpinstanc:[37,66],gcpiprul:[37,66],gcpnetworkinterfac:[37,66],gcpnetworktag:[37,66],gcpnicaccessconfig:[37,66],gcporgan:[37,66],gcpproject:[37,66],gcprecordset:[37,66],gcpsubnet:[37,66],gcpvpc:[37,66],get:5,github:[38,39,40,65,66],githubbranch:[40,66],githuborgan:[40,66],githubrepositori:[40,66],githubteam:[40,66],githubus:[40,66],given:[65,67],gkeclust:[37,66],goal:4,googl:[36,42],grant:[65,67],gsuit:[41,42,43,66],gsuitegroup:[43,66],gsuiteus:[25,43,66],guid:[1,62],handl:5,have:[65,67],host:4,how:[1,4,5,12,63,65,67],human:52,i:[65,67],imag:62,implement:1,includ:3,index:5,indirectli:65,individu:1,infrastructur:62,instal:[8,65,67],instanc:[4,63,65,67],instead:63,intel:[1,5],internet:[4,63,65,67],ip:[13,66],ippermissioninbound:[13,37,66],iprang:[37,66],iprul:[13,37,66],jamf:[45,46,66],jamfcomputergroup:[46,66],job:[4,62,67],kmsalia:[13,66],kmsgrant:[13,66],kmskei:[13,66],kubernet:[47,48,49,66],kubernetesclust:[49,66],kubernetescontain:[49,66],kubernetesnamespac:[49,66],kubernetespod:[49,66],kubernetessecret:[49,66],kubernetesservic:[49,66],label:[37,66,67],languag:65,lastpass:[18,50,51,52],lastpassus:52,lastupd:5,launchconfigur:[13,66],launchtempl:[13,66],launchtemplatevers:[13,66],learn:67,level:[65,67],load:[5,65],loadbalanc:[13,65,66],loadbalancerv2:[13,65,66],logic:4,maintain:62,make:5,manag:5,mani:[65,67],manual:1,map:[12,67],meet:0,metadata:[9,66],method:41,microsoft:15,modul:[1,5],modulesyncmetadata:[9,66],more:67,multipl:[10,35],my:[4,65,67],name:67,nameserv:[13,66],need:5,neo4j:4,networkinterfac:[13,66],node:[5,67],notat:66,note:[3,5,66],oauth:41,observ:62,off:[65,67],okta:[53,54,55,66],oktaadministrationrol:[55,66],oktaappl:[55,66],oktagroup:[55,66],oktaorgan:[55,66],oktatrustedorigin:[55,66],oktaus:[55,66],oktauserfactor:[55,66],onli:5,oper:62,option:5,other:[5,67],our:4,overview:4,packag:[13,66],pagerduti:[56,57,58,66],pagerdutyescalationpolici:[58,66],pagerdutyintegr:[58,66],pagerdutyschedul:[58,66],pagerdutyschedulelay:[58,66],pagerdutyservic:[58,66],pagerdutyteam:[58,66],pagerdutyus:[58,66],perform:5,permalink:67,permiss:[12,67],pictur:62,plain:4,polici:[65,67],possibl:67,principl:5,programminglanguag:[40,66],project:35,properti:[5,67],protip:67,pythonlibrari:[40,66],queri:[5,65],quick:[63,66],rd:[65,67],rdscluster:[13,66],rdsinstanc:[13,66],rdssnapshot:[13,66],recap:4,redshiftclust:[13,66],relationship:[5,13,16,19,22,25,28,31,34,37,40,43,46,49,52,55,58,61,66],repli:[55,66],repo:65,repositori:65,requir:5,result:5,risk:[13,66],riski:65,run:[1,4,5,63],s3:[65,67],s3acl:[13,66],s3bucket:[13,66],s3policystat:[13,66],s:[4,5],sampl:65,schema:[5,9,13,16,19,22,25,28,31,34,37,40,43,46,49,52,55,58,61,66],score:65,secretsmanagersecret:[13,66],securityhub:[13,66],semgrep:[59,60,61],semgrepdeploy:61,semgrepscafind:61,semgrepscaloc:61,servic:11,setup:[10,35,63],shortcut:63,singl:10,skeleton:4,sourc:1,spotlightvulner:22,sqsqueue:[13,66],ssminstanceinform:[13,66],ssminstancepatch:[13,66],stage:4,start:5,statsd:62,suppli:5,support:3,sync:[1,5,62],syncmetadata:[9,66],syntax:4,tag:[13,62,66],test:[1,3,5],totallyfak:65,track:63,transform:5,translat:4,turn:[65,67],tutori:67,unencrypt:[65,67],up:[4,62],updat:[4,62],update_tag:5,uri:[55,66],us:[3,12,41,63,65],usag:[3,67],user:65,valid:5,versu:5,view:67,virtualmachin:[16,66],wai:5,web:11,what:[6,7,65,67],which:[4,65,67],why:[6,7],write:[1,5],your:[5,62,67]}}) \ No newline at end of file diff --git a/usage/drift-detect.html b/usage/drift-detect.html new file mode 100644 index 0000000000..832d881bea --- /dev/null +++ b/usage/drift-detect.html @@ -0,0 +1,753 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + How to use Drift-Detection — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+ + +
+
+ +
+

How to use Drift-Detection

+

Drift-Detection is a Cartography module that allows you to track changes of query results over time.

+
+

A Quick Example: Tracking internet-exposed EC2 instances

+

The quickest way to get started using drift-detection is through an example. We showed you how we mark EC2 instances as internet-exposed with Cartography analysis jobs, and now we can use drift-detection to monitor when these instances are added or removed from our accounts over time!

+
+

Setup

+
    +
  1. Specify a ${DRIFT_DETECTION_DIRECTORY} on the machine that runs cartography. This can be any folder where you have read and write access to.

  2. +
  3. Set up a folder structure that looks like this:

    +
       ${DRIFT_DETECTION_DIRECTORY}/
    +   |
    +   |----internet-exposure-query/
    +   |
    +   |----another-query-youre-interested-in/
    +   |
    +   |----yet-another-query-to-track-over-time/
    +
    +As shown here, your ``${DRIFT_DETECTION_DIRECTORY}`` contains one or more ``${QUERY_DIRECTORY}s``.
    +
    +
    +
  4. +
  5. Create a template file

    +
    +

    Save the below contents as ${DRIFT_DETECTION_DIRECTORY}/internet-exposure-query/template.json:

    +
    +
    {
    +  "name": "Internet Exposed EC2 Instances",
    +  "validation_query": "match (n:EC2Instance) where n.exposed_internet = True return n.instancetype, n.privateipaddress, n.publicdnsname, n.exposed_internet_type"
    +  "properties": [],
    +  "results": []
    +}
    +
    +
    +
      +
    • name is a helpful name describing the query.

    • +
    • validation_query is the neo4j Cypher query to track over time. In this case, we have simply asked Neo4j to return instancetype, privateipaddress, publicdnsname, and exposed_internet_type from EC2Instances that Cartography has identified as accessible from the internet. When writing your own queries, note that drift-detection only supports MATCH queries (i.e. read operations). MERGE queries (write operations) are not supported.

    • +
    • properties: Leave this as an empty array. This field is a placeholder that will be filled.

    • +
    • results: Leave this as an empty array. This field is a placeholder that will be filled.

    • +
    +
  6. +
  7. Create a shortcut file

    +
    +

    Save the below contents as ${DRIFT_DETECTION_DIRECTORY}/internet-exposure-query/shortcut.json:

    +
    +
       {
    +     "name": "Internet Exposed EC2 Instances",
    +     "shortcuts": {}
    +   }
    +
    +``name`` should match the ``name`` you specified in ``template.json``.
    +
    +
    +
  8. +
+

All set 👍

+
+
+

Running drift-detection

+
    +
  1. Run ``get-state`` to save results of a query to json

    +
    +

    Run cartography-detectdrift get-state --neo4j-uri <your_neo4j_uri> --drift-detection-directory ${DRIFT_DETECTION_DIRECTORY}

    +

    The internet exposure query might return results that look like this:

    +
    +
       | n.instancetype    | n.privateipaddress    | n.publicdnsname               | n.exposed_internet_type   |
    +   |----------------   |--------------------   |-----------------------------  |-------------------------  |
    +   | c4.large          | 10.255.255.251        | ec2.1.compute.amazonaws.com   | [direct]                  |
    +   | t2.micro          | 10.255.255.252        | ec2.2.compute.amazonaws.com   | [direct]                  |
    +   | c4.large          | 10.255.255.253        | ec2.3.compute.amazonaws.com   | [direct, elb]                 |
    +   | t2.micro          | 10.255.255.254        | ec2.4.compute.amazonaws.com   | [direct, elb]                 |
    +
    +and we should now see a new JSON file ``<unix_timestamp_1>.json`` saved with information in this format:
    +
    +
    +
       {
    +     "name": "Internet Exposed EC2 Instances",
    +     "validation_query": "match (n:EC2Instance) where n.exposed_internet = True return n.instancetype, n.privateipaddress, n.publicdnsname, n.exposed_internet_type"
    +     "properties": ["n.instancetype", "n.privateipaddress", "n.publicdnsname", "n.exposed_internet_type"],
    +     "results": [
    +       ["c4.large", "10.255.255.251", "ec2.1.compute.amazonaws.com", "direct"],
    +       ["t2.micro", "10.255.255.252", "ec2.2.compute.amazonaws.com", "direct"],
    +       ["c4.large", "10.255.255.253", "ec2.3.compute.amazonaws.com", "direct|elb"],
    +       ["t2.micro", "10.255.255.254", "ec2.4.compute.amazonaws.com", "direct|elb"]
    +     ]
    +   }
    +
    +You can continually run ``get-state`` to save the results of a query to json. Each json state file will be named with the Unix timestamp of the time drift-detection was run.
    +
    +
    +
  2. +
  3. Comparing state files

    +
    +

    Now let’s say a couple days go by and some new EC2 Instances were added to our AWS account. We run the get-state command once more and get another file <unix_timestamp_2>.json which looks like this:

    +
    +
       {
    +     "name": "Internet Exposed EC2 Instances",
    +     "validation_query": "match (n:EC2Instance) where n.exposed_internet = True return n.instancetype, n.privateipaddress, n.publicdnsname, n.exposed_internet_type""
    +     "properties": ["n.instancetype", "n.privateipaddress", "n.publicdnsname", "n.exposed_internet_type"],
    +     "results": [
    +       ["t2.micro", "10.255.255.250", "ec2.0.compute.amazonaws.com", "direct"],
    +       ["c4.large", "10.255.255.251", "ec2.1.compute.amazonaws.com", "direct"],
    +       ["t2.micro", "10.255.255.252", "ec2.2.compute.amazonaws.com", "direct"],
    +       ["c4.large", "10.255.255.253", "ec2.3.compute.amazonaws.com", "direct|elb"],
    +       ["c4.large", "10.255.255.255", "ec2.5.compute.amazonaws.com", "direct|elb"]
    +     ]
    +   }
    +
    +It looks like our results list has slightly changed. We can use ``drift-detection`` to quickly diff the two files:
    +
    +
    +
  4. +
+
`cartography-detectdrift get-drift --query-directory ${DRIFT_DETECTION_DIRECTORY}/internet-exposure-query --start-state <unix_timestamp_1>.json --end-state <unix_timestamp_2>.json`
+
+Finally, we should see the following messages pop up:
+
+```
+Query Name: Internet Exposed EC2 Instances
+Query Properties: ["n.instancetype", "n.privateipaddress", "n.publicdnsname", "n.exposed_internet_type"]
+
+New Query Results:
+
+n.instancetype: t2.micro
+n.privateipaddress: 10.255.255.250
+n.publicdnsname: ec2.0.compute.amazonaws.com
+n.exposed_internet_type: ['direct']
+
+n.instancetype: c4.large
+n.privateipaddress: 10.255.255.255
+n.publicdnsname: ec2.5.compute.amazonaws.com
+n.exposed_internet_type: ['direct', 'elb']
+
+Missing Query Results:
+
+n.instancetype: t2.micro
+n.privateipaddress: 10.255.255.253
+n.publicdnsname: ec2.4.compute.amazonaws.com
+n.exposed_internet_type: ['direct', 'elb']
+```
+
+This gives us a quick way to view infrastructure changes!
+
+
+
+
+

Using shortcuts instead of filenames to diff files

+

It can be cumbersome to always type Unix timestamp filenames. To make this easier we can add shortcuts to diff two files without specifying the filename. This lets us bookmark certain states with whatever name we want.

+
    +
  1. Adding shortcuts

    +
    +

    Let’s try adding shortcuts. We will name the first state “first-run” and the second state “second-run” with

    +

    cartography-detectdrift add-shortcut --shortcut first-run --file <unix_timestamp_1>.json

    +

    cartography-detectdrift add-shortcut --shortcut second-run --file <unix_timestamp_2>.json

    +

    We can even use aliases instead of filenames when adding shortcuts!

    +

    cartography-detectdrift add-shortcut --shortcut baseline --file most-recent

    +
    +
  2. +
  3. Comparing state files with shortcuts

    +
    +

    Now that we have shortcuts, we can now simply run

    +

    cartography-detectdrift get-drift --query-directory ${DRIFT_DETECTION_DIRECTORY}/internet-exposure-query --start-state first-run --end-state second-run

    +
    +
  4. +
+

Important note: Each execution of get-state will automatically generate a shortcut in each query directory, most-recent, which will refer to the last state file successfully created in that directory.

+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/usage/index.html b/usage/index.html new file mode 100644 index 0000000000..21f1d55635 --- /dev/null +++ b/usage/index.html @@ -0,0 +1,1351 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <no title> — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+ +
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/usage/samplequeries.html b/usage/samplequeries.html new file mode 100644 index 0000000000..5250e7467b --- /dev/null +++ b/usage/samplequeries.html @@ -0,0 +1,816 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Sample queries — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+ + +
+
+ +
+

Sample queries

+
+

What RDS instances are installed in my AWS accounts?

+
MATCH (aws:AWSAccount)-[r:RESOURCE]->(rds:RDSInstance)
+return *
+
+
+
+
+

Which RDS instances have encryption turned off?

+
MATCH (a:AWSAccount)-[:RESOURCE]->(rds:RDSInstance{storage_encrypted:false})
+return a.name, rds.id
+
+
+
+
+

Which EC2 instances are exposed (directly or indirectly) to the internet?

+
MATCH (instance:EC2Instance{exposed_internet: true})
+RETURN instance.instanceid, instance.publicdnsname
+
+
+
+
+

Which ELB LoadBalancers are internet accessible?

+
MATCH (elb:LoadBalancer{exposed_internet: true})—->(listener:ELBListener)
+RETURN elb.dnsname, listener.port
+ORDER by elb.dnsname, listener.port
+
+
+
+
+

Which ELBv2 LoadBalancerV2s (Application Load Balancers) are internet accessible?

+
MATCH (elbv2:LoadBalancerV2{exposed_internet: true})—->(listener:ELBV2Listener)
+RETURN elbv2.dnsname, listener.port
+ORDER by elbv2.dnsname, listener.port
+
+
+
+
+

Which S3 buckets have a policy granting any level of anonymous access to the bucket?

+
MATCH (s:S3Bucket)
+WHERE s.anonymous_access = true
+RETURN s
+
+
+
+
+

How many unencrypted RDS instances do I have in all my AWS accounts?

+
MATCH (a:AWSAccount)-[:RESOURCE]->(rds:RDSInstance)
+WHERE rds.storage_encrypted = false
+return a.name as AWSAccount, count(rds) as UnencryptedInstances
+
+
+
+
+

What users have the TotallyFake Chrome extension installed?

+
MATCH (u:GSuiteUser)-[r:INSTALLS]->(ext:ChromeExtension)
+WHERE ext.name CONTAINS 'TotallyFake'
+return ext.name, ext.version, u.email
+
+
+
+
+

What users have installed extensions that are risky based on CRXcavator scoring?

+

Risk > 200 is evidence of 3 or more critical risks or many high risks in the extension.

+
MATCH (u:GSuiteUser)-[r:INSTALLS]->(ext:ChromeExtension)
+WHERE ext.risk_total > 200
+return ext.name, ext.version, u.email
+
+
+
+
+

What languages are used in a given GitHub repository?

+
MATCH (:GitHubRepository{name:"myrepo"})-[:LANGUAGE]->(lang:ProgrammingLanguage)
+RETURN lang.name
+
+
+
+
+

What are the dependencies used in a given GitHub repository?

+
MATCH (:GitHubRepository{name:"myrepo"})-[edge:REQUIRES]->(dep:Dependency)
+RETURN dep.name, edge.specifier, dep.version
+
+
+

If you want to filter to just e.g. Python libraries:

+
MATCH (:GitHubRepository{name:"myrepo"})-[edge:REQUIRES]->(dep:Dependency:PythonLibrary)
+RETURN dep.name, edge.specifier, dep.version
+
+
+
+
+

Given a dependency, which GitHub repos depend on it?

+

Using boto3 as an example dependency:

+
MATCH (dep:Dependency:PythonLibrary{name:"boto3"})<-[req:REQUIRES]-(repo:GitHubRepository)
+RETURN repo.name, req.specifier, dep.version
+
+
+
+
+

What are all the dependencies used across all GitHub repos?

+

Just the list of dependencies and their versions:

+
MATCH (dep:Dependency)
+RETURN DISTINCT dep.name AS name, dep.version AS version
+ORDER BY dep.name
+
+
+

With info about which repos are using them:

+
MATCH (repo:GitHubRepository)-[edge:REQUIRES]->(dep:Dependency)
+RETURN repo.name, dep.name, edge.specifier, dep.version
+
+
+

Lyft ingests this information into our internal data stack, +which has enabled us to throw BI tooling on top for easy reporting - +this is highly recommended!

+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/usage/schema.html b/usage/schema.html new file mode 100644 index 0000000000..dad0897362 --- /dev/null +++ b/usage/schema.html @@ -0,0 +1,15589 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cartography Schema — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+

Cartography Schema

+
+

ℹ️ Quick notes on notation

+
    +
  • Bolded words in the schema tables indicate that this field is indexed, so your queries will run faster if you use these fields.

  • +
  • This isn’t proper Neo4j syntax, but for the purpose of this document we will use this notation:

    +
       (NodeTypeA)-[RELATIONSHIP_R]->(NodeTypeB, NodeTypeC, NodeTypeD, NodeTypeE)
    +
    +to mean a shortened version of this:
    +
    +
    +
       (NodeTypeA)-[RELATIONSHIP_R]->(NodeTypeB)
    +   (NodeTypeA)-[RELATIONSHIP_R]->(NodeTypeC)
    +   (NodeTypeA)-[RELATIONSHIP_R]->(NodeTypeD)
    +   (NodeTypeA)-[RELATIONSHIP_R]->(NodeTypeE)
    +
    +In words, this means that ``NodeTypeA`` has ``RELATIONSHIP_R`` pointing to ``NodeTypeB``\ , and ``NodeTypeA`` has ``RELATIONSHIP_R`` pointing to ``NodeTypeC``.
    +
    +
    +
  • +
  • In these docs, more specific nodes will be decorated with GenericNode::SpecificNode notation. For example, if we have a Car node and a RaceCar node, we will refer to the RaceCar as Car::RaceCar.

  • +
+
+
+

Cartography metadata schema

+

Some Cartography sync jobs write nodes to convey information about the job itself. See https://github.com/lyft/cartography/issues/758 for more background on this.

+
+

SyncMetadata:ModuleSyncMetadata

+

This is a node to represent metadata about the sync job of a particular module. Its existence indicates that a particular sync job did happen. +The ‘types’ used here should be actual node labels. For example, if we did sync a particular AWSAccount’s S3Buckets, +the grouptype is ‘AWSAccount’, the groupid is the particular account’s id, and the syncedtype is ‘S3Bucket’.

+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

Source

id

{group_type}_{group_id}_{synced_type}

util.py

grouptype

The parent module’s type

util.py

groupid

The parent module’s id

util.py

syncedtype

The sub-module’s type

util.py

+
+
+
+

AWS Schema

+
+

AWSAccount

+

Representation of an AWS Account.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

name

The name of the account

inscope

Indicates that the account is part of the sync scope (true or false).

foreign

Indicates if the account is not part of the sync scope (true or false). One such example is an account that is trusted as part of cross-account AWSRole trust not in scope for sync.

lastupdated

Timestamp of the last time the node was updated

id

The AWS Account ID number

+
+

Relationships

+
    +
  • Many node types belong to an AWSAccount.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSDNSZone,
    +                      AWSGroup,
    +                      AWSInspectorFinding,
    +                      AWSInspectorPackage,
    +                      AWSLambda,
    +                      AWSPrincipal,
    +                      AWSUser,
    +                      AWSVpc,
    +                      AutoScalingGroup,
    +                      DNSZone,
    +                      DynamoDBTable,
    +                      EBSSnapshot,
    +                      EBSVolume,
    +                      EC2Image,
    +                      EC2Instance,
    +                      EC2Reservation,
    +                      EC2ReservedInstance,
    +                      EC2SecurityGroup,
    +                      ElasticIPAddress,
    +                      ESDomain,
    +                      LaunchConfiguration,
    +                      LaunchTemplate,
    +                      LaunchTemplateVersion,
    +                      LoadBalancer,
    +                      RDSCluster,
    +                      RDSInstance,
    +                      RDSSnapshot,
    +                      SecretsManagerSecret,
    +                      SecurityHub,
    +                      SQSQueue
    +                      SSMInstanceInformation,
    +                      SSMInstancePatch)
    +```
    +
    +
    +
  • +
  • An AWSPolicy node is defined for an AWSAccount.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSPolicy)
    +```
    +
    +
    +
  • +
  • AWSRole nodes are defined in AWSAccount nodes.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSRole)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSCidrBlock

+
+

AWSIpv4CidrBlock

+
+
+

AWSIpv6CidrBlock

+

Representation of an AWS CidrBlock used in VPC configuration. +The AWSCidrBlock defines the base label +type for AWSIpv4CidrBlock and AWSIpv6CidrBlock

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

cidr_block

The CIDR block

block_state

The state of the block

association_id

the association id if the block is associated to a VPC

lastupdated

Timestamp of the last time the node was updated

id

Unique identifier defined with the VPC association and the cidr_block

+
+
+

Relationships

+
    +
  • AWSVpc association

    +
    (AWSVpc)-[BLOCK_ASSOCIATION]->(AWSCidrBlock)
    +
    +
    +
  • +
  • Peering connection where AWSCidrBlock is an accepter or requester cidr.

    +
    (AWSCidrBlock)<-[REQUESTER_CIDR]-(AWSPeeringConnection)
    +(AWSCidrBlock)<-[ACCEPTER_CIDR]-(AWSPeeringConnection)
    +
    +
    +

    Example of high level view of peering (without security group permissions)

    +
    MATCH p=(:AWSAccount)-[:RESOURCE|BLOCK_ASSOCIATION*..]->(:AWSCidrBlock)<-[:ACCEPTER_CIDR]-(:AWSPeeringConnection)-[:REQUESTER_CIDR]->(:AWSCidrBlock)<-[:RESOURCE|BLOCK_ASSOCIATION*..]-(:AWSAccount)
    +RETURN p
    +
    +
    +

    Exploring detailed inbound peering rules

    +
    MATCH (outbound_account:AWSAccount)-[:RESOURCE|BLOCK_ASSOCIATION*..]->(:AWSCidrBlock)<-[:ACCEPTER_CIDR]-(:AWSPeeringConnection)-[:REQUESTER_CIDR]->(inbound_block:AWSCidrBlock)<-[:BLOCK_ASSOCIATION]-(inbound_vpc:AWSVpc)<-[:RESOURCE]-(inbound_account:AWSAccount)
    +WITH inbound_vpc, inbound_block, outbound_account, inbound_account
    +MATCH (inbound_range:IpRange{id: inbound_block.cidr_block})-[:MEMBER_OF_IP_RULE]->(inbound_rule:IpPermissionInbound)-[:MEMBER_OF_EC2_SECURITY_GROUP]->(inbound_group:EC2SecurityGroup)<-[:MEMBER_OF_EC2_SECURITY_GROUP]-(inbound_vpc)
    +RETURN outbound_account.name, inbound_account.name, inbound_range.range, inbound_rule.fromport, inbound_rule.toport, inbound_rule.protocol, inbound_group.name, inbound_vpc.id
    +
    +
    +
  • +
+
+
+
+

AWSGroup

+

Representation of AWS IAM Groups.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

path

The path to the group (IAM identifier, see linked docs above for details)

groupid

Unique string identifying the group

name

The friendly name that identifies the group

createdate

ISO 8601 date-time string when the group was created

arn

The AWS-global identifier for this group

+
+

Relationships

+
    +
  • Objects part of an AWSGroup may assume AWSRoles.

    +
    ```
    +(AWSGroup)-[STS_ASSUMEROLE_ALLOW]->(AWSRole)
    +```
    +
    +
    +
  • +
  • AWSUsers and AWSPrincipals can be members of AWSGroups.

    +
    ```
    +(AWSUser, AWSPrincipal)-[MEMBER_AWS_GROUP]->(AWSGroup)
    +```
    +
    +
    +
  • +
  • AWSGroups belong to AWSAccounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSGroup)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSInspectorFinding

+

Representation of an AWS Inspector Finding

+
+

Relationships

+
    +
  • AWSInspectorFinding may affect EC2 Instances

    +
    (AWSInspectorFinding)-[:AFFECTS]->(EC2Instance)
    +
    +
    +
  • +
  • AWSInspectorFinding may affect ECR Repositories

    +
    (AWSInspectorFinding)-[:AFFECTS]->(ECRRepository)
    +
    +
    +
  • +
  • AWSInspectorFinding may affect ECR Images

    +
    (AWSInspectorFinding)-[:AFFECTS]->(ECRImage)
    +
    +
    +
  • +
  • AWSInspectorFindings belong to AWSAccounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSInspectorFinding)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSInspectorPackage

+

Representation of an AWS Inspector Finding Package

+
+

Relationships

+
    +
  • AWSInspectorFindings have AWSInspectorPackages.

    +
    ```
    +(AWSInspectorFindings)-[HAS]->(AWSInspectorPackages)
    +```
    +
    +
    +
  • +
  • AWSInspectorPackages belong to AWSAccounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSInspectorPackages)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSLambda

+

Representation of an AWS Lambda Function.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The arn of the lambda function

name

The name of the lambda function

modifieddate

Timestamp of the last time the function was last updated

runtime

The runtime environment for the Lambda function

description

The description of the Lambda function

timeout

The amount of time in seconds that Lambda allows a function to run before stopping it

memory

The memory that’s allocated to the function

codesize

The size of the function’s deployment package, in bytes.

handler

The function that Lambda calls to begin executing your function.

version

The version of the Lambda function.

tracingconfigmode

The function’s AWS X-Ray tracing configuration mode.

revisionid

The latest updated revision of the function or alias.

state

The current state of the function.

statereason

The reason for the function’s current state.

statereasoncode

The reason code for the function’s current state.

lastupdatestatus

The status of the last update that was performed on the function.

lastupdatestatusreason

The reason for the last update that was performed on the function.

lastupdatestatusreasoncode

The reason code for the last update that was performed on the function.

packagetype

The type of deployment package.

signingprofileversionarn

The ARN of the signing profile version.

signingjobarn

The ARN of the signing job.

codesha256

The SHA256 hash of the function’s deployment package.

architectures

The instruction set architecture that the function supports. Architecture is a string array with one of the valid values.

masterarn

For Lambda@Edge functions, the ARN of the main function.

kmskeyarn

The KMS key that’s used to encrypt the function’s environment variables. This key is only returned if you’ve configured a customer managed key.

+
+

Relationships

+
    +
  • AWSLambda function are resources in an AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSLambda)
    +```
    +
    +
    +
  • +
  • AWSLambda functions may act as AWSPrincipals via role assumption.

    +
    ```
    +(AWSLambda)-[STS_ASSUME_ROLE_ALLOW]->(AWSPrincipal)
    +```
    +
    +
    +
  • +
  • AWSLambda functions may also have aliases.

    +
    ```
    +(AWSLambda)-[KNOWN_AS]->(AWSLambdaFunctionAlias)
    +```
    +
    +
    +
  • +
  • AWSLambda functions may have the resource AWSLambdaEventSourceMapping.

    +
    ```
    +(AWSLambda)-[RESOURCE]->(AWSLambdaEventSourceMapping)
    +```
    +
    +
    +
  • +
  • AWSLambda functions has AWS Lambda Layers.

    +
    ```
    +(AWSLambda)-[HAS]->(AWSLambdaLayer)
    +```
    +
    +
    +
  • +
  • AWSLambda functions has AWS ECR Images.

    +
    ```
    +(AWSLambda)-[HAS]->(ECRImage)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSLambdaFunctionAlias

+

Representation of an AWSLambdaFunctionAlias.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The arn of the lambda function alias

name

The name of the lambda function alias

functionversion

The function version that the alias invokes.

revisionid

A unique identifier that changes when you update the alias.

description

The description of the alias.

+
+

Relationships

+
    +
  • AWSLambda functions may also have aliases.

    +
    ```
    +(AWSLambda)-[KNOWN_AS]->(AWSLambdaFunctionAlias)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSLambdaEventSourceMapping

+

Representation of an AWSLambdaEventSourceMapping.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The id of the event source mapping

batchsize

The maximum number of items to retrieve in a single batch.

startingposition

The position in a stream from which to start reading.

startingpositiontimestamp

The time from which to start reading.

parallelizationfactor

The number of batches to process from each shard concurrently.

maximumbatchingwindowinseconds

The maximum amount of time to gather records before invoking the function, in seconds.

eventsourcearn

The Amazon Resource Name (ARN) of the event source.

lastmodified

The date that the event source mapping was last updated, or its state changed.

state

The state of the event source mapping.

maximumrecordage

Discard records older than the specified age.

bisectbatchonfunctionerror

If the function returns an error, split the batch in two and retry.

maximumretryattempts

Discard records after the specified number of retries.

tumblingwindowinseconds

The duration in seconds of a processing window.

lastprocessingresult

The result of the last AWS Lambda invocation of your Lambda function.

+
+

Relationships

+
    +
  • AWSLambda functions may have the resource AWSLambdaEventSourceMapping.

    +
    ```
    +(AWSLambda)-[RESOURCE]->(AWSLambdaEventSourceMapping)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSLambdaLayer

+

Representation of an AWSLambdaLayer.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The arn of the lambda function layer

codesize

The size of the layer archive in bytes.

signingprofileversionarn

The Amazon Resource Name (ARN) for a signing profile version.

signingjobarn

The Amazon Resource Name (ARN) of a signing job.

+
+

Relationships

+
    +
  • AWSLambda functions has AWS Lambda Layers.

    +
    ```
    +(AWSLambda)-[HAS]->(AWSLambdaLayer)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSPolicy

+

Representation of an AWS Policy.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

name

The friendly name (not ARN) identifying the policy

createdate

ISO 8601 date-time when the policy was created

type

“inline” or “managed” - the type of policy it is

arn

The arn for this object

id

The unique identifer for a policy. If the policy is managed this will be the Arn. If the policy is inline this will calculated as AWSPrincipal/inline_policy/PolicyName

+
+

Relationships

+
    +
  • AWSPrincipal contains AWSPolicy

    +
    ```
    +(AWSPrincipal)-[POLICY]->(AWSPolicy)
    +```
    +
    +
    +
  • +
  • AWSPolicy contains AWSPolicyStatement

    +
    ```
    +(AWSPolicy)-[STATEMENTS]->(AWSPolicyStatement)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSPolicyStatement

+

Representation of an AWS Policy Statement.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

resources

(array) The resources the statement is applied to. Can contain wildcards

actions

(array) The permissions allowed or denied by the statement. Can contain wildcards

notactions

(array) The permission explicitly not matched by the statement

effect

“Allow” or “Deny” - the effect of this statement

id

The unique identifier for a statement.
If the statement has an Sid the id will be calculated as AWSPolicy.id/statements/Sid.
If the statement has no Sid the id will be calculated as AWSPolicy.id/statements/index of statement in statement list

+
+

Relationships

+
    +
  • AWSPolicy contains AWSPolicyStatement

    +
    ```
    +(AWSPolicy)-[STATEMENTS]->(AWSPolicyStatement)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSPrincipal

+

Representation of an AWSPrincipal.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

path

The path to the principal

name

The friendly name of the principal

createdate

ISO 8601 date-time when the principal was created

arn

AWS-unique identifier for this object

userid

The stable and unique string identifying the principal.

passwordlastused

Datetime when this principal’s password was last used

+
+

Relationships

+
    +
  • AWS Principals can be members of AWS Groups.

    +
    ```
    +(AWSPrincipal)-[MEMBER_AWS_GROUP]->(AWSGroup)
    +```
    +
    +
    +
  • +
  • This AccountAccessKey is used to authenticate to this AWSPrincipal.

    +
    ```
    +(AWSPrincipal)-[AWS_ACCESS_KEY]->(AccountAccessKey)
    +```
    +
    +
    +
  • +
  • AWS Roles can trust AWS Principals.

    +
    (AWSRole)-[TRUSTS_AWS_PRINCIPAL]->(AWSPrincipal)
    +
    +
    +
  • +
  • AWS Accounts contain AWS Principals.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSPrincipal)
    +```
    +
    +
    +
  • +
  • Redshift clusters may assume IAM roles. See this article.

    +
    (RedshiftCluster)-[STS_ASSUMEROLE_ALLOW]->(AWSPrincipal)
    +
    +
    +
  • +
+
+
+
+

AWSPrincipal::AWSUser

+

Representation of an AWSUser. An AWS User is a type of AWS Principal.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

path

The path to the user

name

The friendly name of the user

createdate

ISO 8601 date-time when the user was created

arn

AWS-unique identifier for this object

userid

The stable and unique string identifying the user.

passwordlastused

Datetime when this user’s password was last used

+
+

Relationships

+
    +
  • AWS Users can be members of AWS Groups.

    +
    ```
    +(AWSUser)-[MEMBER_AWS_GROUP]->(AWSGroup)
    +```
    +
    +
    +
  • +
  • AWS Users can assume AWS Roles.

    +
    ```
    +(AWSUser)-[STS_ASSUMEROLE_ALLOW]->(AWSRole)
    +```
    +
    +
    +
  • +
  • This AccountAccessKey is used to authenticate to this AWSUser

    +
    ```
    +(AWSUser)-[AWS_ACCESS_KEY]->(AccountAccessKey)
    +```
    +
    +
    +
  • +
  • AWS Accounts contain AWS Users.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSUser)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSPrincipal::AWSRole

+

Representation of an AWS IAM Role. An AWS Role is a type of AWS Principal.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

roleid

The stable and unique string identifying the role.

name

The friendly name that identifies the role.

createdate

The date and time, in ISO 8601 date-time format, when the role was created.

arn

AWS-unique identifier for this object

+
+

Relationships

+
    +
  • Some AWS Groups, Users, Principals, and EC2 Instances can assume AWS Roles.

    +
    (AWSGroup, AWSUser, EC2Instance)-[STS_ASSUMEROLE_ALLOW]->(AWSRole)
    +
    +
    +
  • +
  • Some AWS Roles can assume other AWS Roles.

    +
    (AWSRole)-[STS_ASSUMEROLE_ALLOW]->(AWSRole)
    +
    +
    +
  • +
  • Some AWS Roles trust AWS Principals.

    +
    (AWSRole)-[TRUSTS_AWS_PRINCIPAL]->(AWSPrincipal)
    +
    +
    +
  • +
  • AWS Roles are defined in AWS Accounts.

    +
    (AWSAccount)-[RESOURCE]->(AWSRole)
    +
    +
    +
  • +
+
+
+
+

AWSTransitGateway

+

Representation of an AWS Transit Gateway.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

owner_id

The ID of the AWS account that owns the transit gateway

description

Transit Gateway description

state

Can be one of pending | available | modifying | deleting | deleted

tgw_id

Unique identifier of the Transit Gateway

id

Unique identifier of the Transit Gateway

arn

AWS-unique identifier for this object (same as id)

+
+

Relationships

+
    +
  • Transit Gateways belong to one AWSAccount

    +
    (AWSAccount)-[RESOURCE]->(AWSTransitGateway)
    +
    +
    +
  • +
  • … and can be shared with other accounts

    +
    (AWSAccount)<-[SHARED_WITH]-(AWSTransitGateway)
    +
    +
    +
  • +
  • AWSTag

    +
    (AWSTransitGateway)-[TAGGED]->(AWSTag)
    +
    +
    +
  • +
+
+
+
+

AWSTransitGatewayAttachment

+

Representation of an AWS Transit Gateway Attachment.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

resource_type

Can be one of vpc | vpn | direct-connect-gateway | tgw-peering

state

Can be one of initiating | pendingAcceptance | rollingBack | pending | available | modifying | deleting | deleted | failed | rejected | rejecting | failing

id

Unique identifier of the Transit Gateway Attachment

+
+

Relationships

+
    +
  • AWSAccount

    +
    (AWSAccount)-[RESOURCE]->(AWSTransitGatewayAttachment)
    +
    +
    +
  • +
  • AWSVpc (for VPC attachments)

    +
    (AWSVpc)-[RESOURCE]->(AWSTransitGatewayAttachment {resource_type: 'vpc'})
    +
    +
    +
  • +
  • AWSTransitGateway attachment

    +
    (AWSTransitGateway)<-[ATTACHED_TO]-(AWSTransitGatewayAttachment)
    +
    +
    +
  • +
  • AWSTag

    +
    (AWSTransitGatewayAttachment)-[TAGGED]->(AWSTag)
    +
    +
    +
  • +
+
+
+
+

AWSVpc

+

Representation of an AWS CidrBlock used in VPC configuration. +More information on https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-vpcs.html

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

vpcid

The VPC unique identifier

primary_cidr_block

The primary IPv4 CIDR block for the VPC.

instance_tenancy

The allowed tenancy of instances launched into the VPC.

state

The current state of the VPC.

region

(optional) the region of this VPC. This field is only available on VPCs in your account. It is not available on VPCs that are external to your account and linked via a VPC peering relationship.

id

Unique identifier defined VPC node (vpcid)

+
+

Relationships

+
    +
  • AWSAccount resource

    +
    (AWSAccount)-[RESOURCE]->(AWSVpc)
    +
    +
    +
  • +
  • AWSVpc and AWSCidrBlock association

    +
    (AWSVpc)-[BLOCK_ASSOCIATION]->(AWSCidrBlock)
    +
    +
    +
  • +
  • AWSVpc and EC2SecurityGroup membership association

    +
    (AWSVpc)<-[MEMBER_OF_EC2_SECURITY_GROUP]-(EC2SecurityGroup)
    +
    +
    +
  • +
  • AWS VPCs can be tagged with AWSTags.

    +
    (AWSVpc)-[TAGGED]->(AWSTag)
    +
    +
    +
  • +
  • Redshift clusters can be members of AWSVpcs.

    +
    (RedshiftCluster)-[MEMBER_OF_AWS_VPC]->(AWSVpc)
    +
    +
    +
  • +
  • Peering connection where AWSVpc is an accepter or requester vpc.

    +
    (AWSVpc)<-[REQUESTER_VPC]-(AWSPeeringConnection)
    +(AWSVpc)<-[ACCEPTER_VPC]-(AWSPeeringConnection)
    +
    +
    +
  • +
+
+
+
+

Tag::AWSTag

+

Representation of an AWS Tag. AWS Tags can be applied to many objects.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

This tag’s unique identifier of the format {TagKey}:{TagValue}. We fabricated this ID.

key

One part of a key-value pair that makes up a tag.

value

One part of a key-value pair that makes up a tag.

region

The region where this tag was discovered.

+
+

Relationships

+
    +
  • AWS VPCs, DB Subnet Groups, EC2 Instances, EC2 SecurityGroups, EC2 Subnets, EC2 Network Interfaces, RDS Instances, and S3 Buckets can be tagged with AWSTags.

    +
    (AWSVpc, DBSubnetGroup, EC2Instance, EC2SecurityGroup, EC2Subnet, NetworkInterface, RDSInstance, S3Bucket)-[TAGGED]->(AWSTag)
    +
    +
    +
  • +
+
+
+
+

AccountAccessKey

+

Representation of an AWS Access Key.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

createdate

Date when access key was created

status

Active: valid for API calls. Inactive: not valid for API calls

lastuseddate

Date when the key was last used

lastusedservice

The service that was last used with the access key

lastusedregion

The region where the access key was last used

accesskeyid

The ID for this access key

+
+

Relationships

+
    +
  • Account Access Keys may authenticate AWS Users and AWS Principal objects.

    +
    ```
    +(AWSUser, AWSPrincipal)-[AWS_ACCESS_KEY]->(AccountAccessKey)
    +```
    +
    +
    +
  • +
+
+
+
+

DBSubnetGroup

+

Representation of an RDS DB Subnet Group. For more information on how RDS instances interact with these, please see this article.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

id

The ARN of the DBSubnetGroup

name

The name of DBSubnetGroup

lastupdated

Timestamp of the last time the node was updated

description

Description of the DB Subnet Group

status

The status of the group

vpc_id

The ID of the VPC (Virtual Private Cloud) that this DB Subnet Group is associated with.

value

The IP address that the DNSRecord points to

+
+

Relationships

+
    +
  • RDS Instances are part of DB Subnet Groups

    +
    (RDSInstance)-[:MEMBER_OF_DB_SUBNET_GROUP]->(DBSubnetGroup)
    +
    +
    +
  • +
  • DB Subnet Groups consist of EC2 Subnets

    +
    (DBSubnetGroup)-[:RESOURCE]->(EC2Subnet)
    +
    +
    +
  • +
  • DB Subnet Groups can be tagged with AWSTags.

    +
    ```
    +(DBSubnetGroup)-[TAGGED]->(AWSTag)
    +```
    +
    +
    +
  • +
+
+
+
+

DNSRecord

+

Representation of a generic DNSRecord.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

name

The name of the DNSRecord

lastupdated

Timestamp of the last time the node was updated

id

The name of the DNSRecord concatenated with the record type

type

The record type of the DNS record

value

The IP address that the DNSRecord points to

+
+

Relationships

+
    +
  • DNSRecords can point to IP addresses.

    +
    ```
    +(DNSRecord)-[DNS_POINTS_TO]->(Ip)
    +```
    +
    +
    +
  • +
  • DNSRecords/AWSDNSRecords can point to each other.

    +
    ```
    +(AWSDNSRecord, DNSRecord)-[DNS_POINTS_TO]->(AWSDNSRecord, DNSRecord)
    +```
    +
    +
    +
  • +
  • DNSRecords can point to LoadBalancers.

    +
    ```
    +(DNSRecord)-[DNS_POINTS_TO]->(LoadBalancer)
    +```
    +
    +
    +
  • +
  • DNSRecords can be members of DNSZones.

    +
    ```
    +(DNSRecord)-[MEMBER_OF_DNS_ZONE]->(DNSZone)
    +```
    +
    +
    +
  • +
+
+
+
+

DNSRecord::AWSDNSRecord

+

Representation of an AWS DNS ResourceRecordSet.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

name

The name of the DNSRecord

lastupdated

Timestamp of the last time the node was updated

id

The zoneid for the record, the value of the record, and the type concatenated together

type

The record type of the DNS record

value

If it is an A, ALIAS, or CNAME record, this is the IP address that the DNSRecord points to. If it is an NS record, the name is used here.

+
+

Relationships

+
    +
  • DNSRecords/AWSDNSRecords can point to each other.

    +
    ```
    +(AWSDNSRecord, DNSRecord)-[DNS_POINTS_TO]->(AWSDNSRecord, DNSRecord)
    +```
    +
    +
    +
  • +
  • AWSDNSRecords can point to LoadBalancers.

    +
    ```
    +(AWSDNSRecord)-[DNS_POINTS_TO]->(LoadBalancer, ESDomain)
    +```
    +
    +
    +
  • +
  • AWSDNSRecords can be members of AWSDNSZones.

    +
    ```
    +(AWSDNSRecord)-[MEMBER_OF_DNS_ZONE]->(AWSDNSZone)
    +```
    +
    +
    +
  • +
+
+
+
+

DNSZone

+

Representation of a generic DNS Zone.

+ ++++ + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

name

the name of the DNS zone

comment

Comments about the zone

+
+

Relationships

+
    +
  • DNSRecords can be members of DNSZones.

    +
    ```
    +(DNSRecord)-[MEMBER_OF_DNS_ZONE]->(DNSZone)
    +```
    +
    +
    +
  • +
+
+
+
+

DNSZone::AWSDNSZone

+

Representation of an AWS DNS HostedZone.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

name

the name of the DNS zone

zoneid

The zoneid defined by Amazon Route53

lastupdated

Timestamp of the last time the node was updated

comment

Comments about the zone

privatezone

Whether or not this is a private DNS zone

+
+

Relationships

+
    +
  • AWSDNSZones and DNSZones can be part of AWSAccounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSDNSZone)
    +```
    +
    +
    +
  • +
  • AWSDNSRecords can be members of AWSDNSZones.

    +
    ```
    +(AWSDNSRecord)-[MEMBER_OF_DNS_ZONE]->(AWSDNSZone)
    +```
    +
    +
    +
  • +
  • AWSDNSZone can have subzones hosted by another AWSDNSZone

    +
    ```
    +(AWSDNSZone)<-[SUBZONE]-(AWSDNSZone)
    +```
    +
    +
    +
  • +
+
+
+
+

DynamoDBTable

+

Representation of an AWS DynamoDBTable.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

name

The name of the table

id

The ARN of the table

region

The AWS region of the table

arn

The AWS-unique identifier

+
+

Relationships

+
    +
  • DynamoDBTables belong to AWS Accounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(DynamoDBTable)
    +```
    +
    +
    +
  • +
+
+
+
+

EC2Instance

+

Our representation of an AWS EC2 Instance.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Same as instanceid below.

instanceid

The instance id provided by AWS. This is globally unique

publicdnsname

The public DNS name assigned to the instance

publicipaddress

The public IPv4 address assigned to the instance if applicable

privateipaddress

The private IPv4 address assigned to the instance

imageid

The ID of the Amazon Machine Image used to launch the instance

subnetid

The ID of the EC2Subnet associated with this instance

instancetype

The instance type. See API docs linked above for specifics.

iaminstanceprofile

The IAM instance profile associated with the instance, if applicable.

launchtime

The time the instance was launched

monitoringstate

Whether monitoring is enabled. Valid Values: disabled, disabling, enabled, pending.

state

The current state of the instance.

launchtimeunix

The time the instance was launched in unix time

region

The AWS region this Instance is running in

exposed_internet

The exposed_internet flag on an EC2 instance is set to True when (1) the instance is part of an EC2 security group or is connected to a network interface connected to an EC2 security group that allows connectivity from the 0.0.0.0/0 subnet or (2) the instance is connected to an Elastic Load Balancer that has its own exposed_internet flag set to True.

availabilityzone

The Availability Zone of the instance.

tenancy

The tenancy of the instance.

hostresourcegrouparn

The ARN of the host resource group in which to launch the instances.

platform

The value is Windows for Windows instances; otherwise blank.

architecture

The architecture of the image.

ebsoptimized

Indicates whether the instance is optimized for Amazon EBS I/O.

bootmode

The boot mode of the instance.

instancelifecycle

Indicates whether this is a Spot Instance or a Scheduled Instance.

hibernationoptions

Indicates whether the instance is enabled for hibernation.

+
+

Relationships

+
    +
  • EC2 Instances can be part of subnets

    +
    ```
    +(EC2Instance)-[PART_OF_SUBNET]->(EC2Subnet)
    +```
    +
    +
    +
  • +
  • EC2 Instances can have NetworkInterfaces connected to them

    +
    ```
    +(EC2Instance)-[NETWORK_INTERFACE]->(NetworkInterface)
    +```
    +
    +
    +
  • +
  • EC2 Instances may be members of EC2 Reservations

    +
    ```
    +(EC2Instance)-[MEMBER_OF_EC2_RESERVATION]->(EC2Reservation)
    +```
    +
    +
    +
  • +
  • EC2 Instances can be part of EC2 Security Groups

    +
    ```
    +(EC2Instance)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup)
    +```
    +
    +
    +
  • +
  • Load Balancers can expose (be connected to) EC2 Instances

    +
    ```
    +(LoadBalancer)-[EXPOSE]->(EC2Instance)
    +```
    +
    +
    +
  • +
  • Package and Dependency nodes can be deployed in EC2 Instances.

    +
    ```
    +(Package, Dependency)-[DEPLOYED]->(EC2Instance)
    +```
    +
    +
    +
  • +
  • AWS Accounts contain EC2 Instances.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(EC2Instance)
    +```
    +
    +
    +
  • +
  • EC2 Instances can be tagged with AWSTags.

    +
    ```
    +(EC2Instance)-[TAGGED]->(AWSTag)
    +```
    +
    +
    +
  • +
  • AWS EBS Volumes are attached to an EC2 Instance

    +
    ```
    +(EBSVolume)-[ATTACHED_TO]->(EC2Instance)
    +```
    +
    +
    +
  • +
  • EC2 Instances can assume IAM Roles.

    +
    ```
    +(EC2Instance)-[STS_ASSUMEROLE_ALLOW]->(AWSRole)
    +```
    +
    +
    +
  • +
  • EC2Instances can have SSMInstanceInformation

    +
    ```
    +(EC2Instance)-[HAS_INFORMATION]->(SSMInstanceInformation)
    +```
    +
    +
    +
  • +
  • EC2Instances can have SSMInstancePatches

    +
    ```
    +(EC2Instance)-[HAS_PATCH]->(SSMInstancePatch)
    +```
    +
    +
    +
  • +
+
+
+
+

EC2KeyPair

+

Representation of an AWS EC2 Key Pair

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

keyname

The name of the key pair

keyfingerprint

The fingerprint of the public key

region

The AWS region

arn

AWS-unique identifier for this object

id

same as arn

user_uploaded

user_uploaded is set to True if the the KeyPair was uploaded to AWS. Uploaded KeyPairs will have 128-bit MD5 hashed keyfingerprint, and KeyPairs from AWS will have 160-bit SHA-1 hashed keyfingerprints.

duplicate_keyfingerprint

duplicate_keyfingerprint is set to True if the KeyPair has the same keyfingerprint as another KeyPair.

+
+

Relationships

+
    +
  • EC2 key pairs are contained in AWS Accounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(EC2KeyPair)
    +```
    +
    +
    +
  • +
  • EC2 key pairs can be used to log in to AWS EC2 isntances.

    +
    ```
    +(EC2KeyPair)-[SSH_LOGIN_TO]->(EC2Instance)
    +```
    +
    +
    +
  • +
  • EC2 key pairs have matching keyfingerprint.

    +
    ```
    +(EC2KeyPair)-[MATCHING_FINGERPRINT]->(EC2KeyPair)
    +```
    +
    +
    +
  • +
+
+
+
+

EC2PrivateIp

+

Representation of an AWS EC2 InstancePrivateIpAddress

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

network_interface_id

id of the network interface with which the IP is associated with

primary

Indicates whether this IPv4 address is the primary private IP address of the network interface.

private_ip_address

The private IPv4 address of the network interface.

public_ip

The public IP address or Elastic IP address bound to the network interface.

ip_owner_id

Id of the owner, e.g. amazon-elb for ELBs

+
+

Relationships

+
    +
  • EC2PrivateIps are connected with NetworkInterfaces.

    +
    ```
    +(NetworkInterface)-[PRIVATE_IP_ADDRESS]->(EC2PrivateIp)
    +```
    +
    +
    +
  • +
+
+
+
+

EC2Reservation

+

Representation of an AWS EC2 Reservation.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

requesterid

The ID of the requester that launched the instances on your behalf

reservationid

The ID of the reservation.

region

The AWS region

ownerid

The ID of the AWS account that owns the reservation.

+
+

Relationships

+
    +
  • EC2 reservations are contained in AWS Accounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(EC2Reservation)
    +```
    +
    +
    +
  • +
  • EC2 Instances are members of EC2 reservations.

    +
    ```
    +(EC2Instance)-[MEMBER_OF_EC2_RESERVATION]->(EC2Reservation)
    +```
    +
    +
    +
  • +
+
+
+
+

EC2SecurityGroup

+

Representation of an AWS EC2 Security Group.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

groupid

The ID of the security group

name

The name of the security group

description

A description of the security group

id

Same as groupid

region

The AWS region this security group is installed in

+
+

Relationships

+
    +
  • EC2 Instances, Network Interfaces, Load Balancers, Elastic Search Domains, IP Rules, IP Permission Inbound nodes, and RDS Instances can be members of EC2 Security Groups.

    +
    ```
    +(EC2Instance,
    + NetworkInterface,
    + LoadBalancer,
    + ESDomain,
    + IpRule,
    + IpPermissionInbound,
    + RDSInstance,
    + AWSVpc)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup)
    +```
    +
    +
    +
  • +
  • Load balancers can define inbound Source Security Groups.

    +
    ```
    +(LoadBalancer)-[SOURCE_SECURITY_GROUP]->(EC2SecurityGroup)
    +```
    +
    +
    +
  • +
  • AWS Accounts contain EC2 Security Groups.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(EC2SecurityGroup)
    +```
    +
    +
    +
  • +
  • EC2 SecurityGroups can be tagged with AWSTags.

    +
    ```
    +(EC2SecurityGroup)-[TAGGED]->(AWSTag)
    +```
    +
    +
    +
  • +
  • Redshift clusters can be members of EC2 Security Groups.

    +
    (RedshiftCluster)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup)
    +
    +
    +
  • +
+
+
+
+

EC2Subnet

+

Representation of an AWS EC2 Subnet.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

subnetid

The ID of the subnet

id

same as subnetid

region

The AWS region the subnet is installed on

name

The IPv4 CIDR block assigned to the subnet

cidr_block

The IPv4 CIDR block assigned to the subnet

available_ip_address_count

The number of unused private IPv4 addresses in the subnet. The IPv4 addresses for any stopped instances are considered unavailable

default_for_az

Indicates whether this is the default subnet for the Availability Zone.

map_customer_owned_ip_on_launch

Indicates whether a network interface created in this subnet (including a network interface created by RunInstances ) receives a customer-owned IPv4 address

map_public_ip_on_launch

Indicates whether instances launched in this subnet receive a public IPv4 address

subnet_arn

The Amazon Resource Name (ARN) of the subnet

availability_zone

The Availability Zone of the subnet

availability_zone_id

The AZ ID of the subnet

state

The current state of the subnet.

assignipv6addressoncreation

Indicates whether a network interface created in this subnet (including a network interface created by RunInstances ) receives an IPv6 address.

+
+

Relationships

+
    +
  • A Network Interface can be part of an EC2 Subnet.

    +
    ```
    +(NetworkInterface)-[PART_OF_SUBNET]->(EC2Subnet)
    +```
    +
    +
    +
  • +
  • An EC2 Instance can be part of an EC2 Subnet.

    +
    ```
    +(EC2Instance)-[PART_OF_SUBNET]->(EC2Subnet)
    +```
    +
    +
    +
  • +
  • A LoadBalancer can be part of an EC2 Subnet.

    +
    ```
    +(LoadBalancer)-[SUBNET]->(EC2Subnet)
    +
    +```
    +
    +
    +
  • +
  • A LoadBalancer can be part of an EC2 Subnet.

    +
    ```
    +(LoadBalancer)-[PART_OF_SUBNET]->(EC2Subnet)
    +```
    +
    +
    +
  • +
  • A LoadBalancerV2 can be part of an EC2 Subnet.

    +
    ```
    +(LoadBalancerV2)-[PART_OF_SUBNET]->(EC2Subnet)
    +```
    +
    +
    +
  • +
  • DB Subnet Groups consist of EC2 Subnets

    +
    (DBSubnetGroup)-[RESOURCE]->(EC2Subnet)
    +
    +
    +
  • +
  • EC2 Subnets can be tagged with AWSTags.

    +
    ```
    +(EC2Subnet)-[TAGGED]->(AWSTag)
    +```
    +
    +
    +
  • +
  • EC2 Subnets are member of a VPC.

    +
    ```
    +(EC2Subnet)-[MEMBER_OF_AWS_VPC]->(AWSVpc)
    +```
    +
    +
    +
  • +
  • EC2 Subnets belong to AWS Accounts

    +
    ```
    +(AWSAccount)-[RESOURCE]->(EC2Subnet)
    +```
    +
    +
    +
  • +
  • EC2PrivateIps are connected with NetworkInterfaces.

    +
    (NetworkInterface)-[PRIVATE_IP_ADDRESS]->(EC2PrivateIp)
    +
    +
    +
  • +
+
+
+
+

AWSInternetGateway

+
+

Representation of an AWS Interent Gateway.

+
+ ++++ + + + + + + + + + + + + + + + + +

Field

Description

id

Internet gateway ID

arn

Amazon Resource Name

region

The region of the gateway

+
+

Relationships

+
    +
  • Internet Gateways are attached to a VPC.

    +
    ```
    +(AWSInternetGateway)-[ATTACHED_TO]->(AWSVpc)
    +```
    +
    +
    +
  • +
  • Internet Gateways belong to AWS Accounts

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSInternetGateway)
    +```
    +
    +
    +
  • +
+
+
+
+

ECRRepository

+

Representation of an AWS Elastic Container Registry Repository.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

id

Same as ARN

arn

The ARN of the repository

name

The name of the repository

region

The region of the repository

created_at

Date and time when the repository was created

+
+

Relationships

+
    +
  • An ECRRepository contains ECRRepositoryImages:

    +
    (:ECRRepository)-[:REPO_IMAGE]->(:ECRRepositoryImage)
    +
    +
    +
  • +
+
+
+
+

ECRRepositoryImage

+

An ECR image may be referenced and tagged by more than one ECR Repository. To best represent this, we’ve created an +ECRRepositoryImage node as a layer of indirection between the repo and the image.

+

More concretely explained, we run +``ecr.list_images()` <https://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_ImageIdentifier.html>`_, and then +store the image tag on an ECRRepositoryImage node and the image digest hash on a separate ECRImage node.

+

This way, more than one ECRRepositoryImage can reference/be connected to the same ECRImage.

+ ++++ + + + + + + + + + + + + + + + + +

Field

Description

tag

The tag applied to the repository image, e.g. “latest”

uri

The URI where the repository image is stored

id

same as uri

+
+

Relationships

+
    +
  • An ECRRepository contains ECRRepositoryImages:

    +
    (:ECRRepository)-[:REPO_IMAGE]->(:ECRRepositoryImage)
    +
    +
    +
  • +
  • ECRRepositoryImages reference ECRImages

    +
    (:ECRRepositoryImage)-[:IMAGE]->(:ECRImage)
    +
    +
    +
  • +
+
+
+
+

ECRImage

+

Representation of an ECR image identified by its digest (e.g. a SHA hash). Specifically, this is the “digest part” of +``ecr.list_images()` <https://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_ImageIdentifier.html>`_. Also see +ECRRepositoryImage.

+ ++++ + + + + + + + + + + + + + +

Field

Description

digest

The hash of this ECR image

id

Same as digest

+
+

Relationships

+
    +
  • ECRRepositoryImages reference ECRImages

    +
    (:ECRRepositoryImage)-[:IMAGE]->(:ECRImage)
    +
    +
    +
  • +
  • Software packages are a part of ECR Images

    +
    (:Package)-[:DEPLOYED]->(:ECRImage)
    +
    +
    +
  • +
+
+
+
+

Package

+

Representation of a software package, as found by an AWS ECR vulnerability scan.

+ ++++ + + + + + + + + + + + + + + + + +

Field

Description

id

Concatenation of {version}|{name}

version

The version of the package, includes the Linux distro that it was built for

name

The name of the package

+
+

Relationships

+
    +
  • Software packages are a part of ECR Images

    +
    (:Package)-[:DEPLOYED]->(:ECRImage)
    +
    +
    +
  • +
  • AWS ECR scans yield ECRScanFindings that affect software packages

    +
    (:ECRScanFindings)-[:AFFECTS]->(:Package)
    +
    +
    +
  • +
+
+
+
+

ECRScanFinding (:Risk:CVE)

+

Representation of a scan finding from AWS ECR. This is the result output of ``ecr.describe_image_scan_findings()` <https://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_DescribeImageScanFindings.html>`_.

+ ++++ + + + + + + + + + + + + + + + + + + + +

Field

Description

name

The name of the ECR scan finding, e.g. a CVE name

id

Same as name

severity

The severity of the risk

uri

A URI link to a descriptive article on the risk

+
+

Relationships

+
    +
  • AWS ECR scans yield ECRScanFindings that affect software packages

    +
    (:ECRScanFindings)-[:AFFECTS]->(:Package)
    +
    +
    +
  • +
+
+
+
+

EKSCluster

+

Representation of an AWS EKS Cluster.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

created_at

The date and time the cluster was created

region

The AWS region

arn

AWS-unique identifier for this object

id

same as arn

name

Name of the EKS Cluster

endpoint

The endpoint for the Kubernetes API server.

endpoint_public_access

Indicates whether the Amazon EKS public API server endpoint is enabled

exposed_internet

Set to True if the EKS Cluster public API server endpoint is enabled

rolearn

The ARN of the IAM role that provides permissions for the Kubernetes control plane to make calls to AWS API

version

Kubernetes version running

platform_version

Version of EKS

status

Status of the cluster. Valid Values: creating, active, deleting, failed, updating

audit_logging

Whether audit logging is enabled

+
+

Relationships

+
    +
  • EKS Clusters belong to AWS Accounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(EKSCluster)
    +```
    +
    +
    +
  • +
+
+
+
+

EMRCluster

+

Representation of an AWS EMR Cluster.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

region

The AWS region

arn

AWS-unique identifier for this object

id

The Id of the EMR Cluster.

instance_collection_type

The instance group configuration of the cluster. A value of INSTANCE_GROUP indicates a uniform instance group configuration. A value of INSTANCE_FLEET indicates an instance fleets configuration.

log_encryption_kms_key_id

The KMS key used for encrypting log files.

requested_ami_version

The AMI version requested for this cluster.

running_ami_version

The AMI version running on this cluster.

release_label

The Amazon EMR release label, which determines the version of open-source application packages installed on the cluster.

auto_terminate

Specifies whether the cluster should terminate after completing all steps.

termination_protected

Indicates whether Amazon EMR will lock the cluster to prevent the EC2 instances from being terminated by an API call or user intervention, or in the event of a cluster error.

visible_to_all_users

Indicates whether the cluster is visible to IAM principals in the Amazon Web Services account associated with the cluster.

master_public_dns_name

The DNS name of the master node. If the cluster is on a private subnet, this is the private DNS name. On a public subnet, this is the public DNS name.

security_configuration

The name of the security configuration applied to the cluster.

autoscaling_role

An IAM role for automatic scaling policies.

scale_down_behavior

The way that individual Amazon EC2 instances terminate when an automatic scale-in activity occurs or an instance group is resized.

custom_ami_id

The ID of a custom Amazon EBS-backed Linux AMI if the cluster uses a custom AMI.

repo_upgrade_on_boot

Specifies the type of updates that are applied from the Amazon Linux AMI package repositories when an instance boots using the AMI.

outpost_arn

The Amazon Resource Name (ARN) of the Outpost where the cluster is launched.

log_uri

The path to the Amazon S3 location where logs for this cluster are stored.

servicerole

Service Role of the EMR Cluster

+
+

Relationships

+
    +
  • EMR Clusters belong to AWS Accounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(EMRCluster)
    +```
    +
    +
    +
  • +
+
+
+
+

ESDomain

+

Representation of an AWS ElasticSearch Domain (see ElasticsearchDomainConfig).

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

elasticsearch_cluster_config_instancetype

The instancetype

elasticsearch_version

The version of elasticsearch

elasticsearch_cluster_config_zoneawarenessenabled

Indicates whether multiple Availability Zones are enabled.

elasticsearch_cluster_config_dedicatedmasterenabled

Indicates whether dedicated master nodes are enabled for the cluster. True if the cluster will use a dedicated master node. False if the cluster will not.

elasticsearch_cluster_config_dedicatedmastercount

Number of dedicated master nodes in the cluster.

elasticsearch_cluster_config_dedicatedmastertype

Amazon ES instance type of the dedicated master nodes in the cluster.

domainid

Unique identifier for an Amazon ES domain.

encryption_at_rest_options_enabled

Specify true to enable encryption at rest.

deleted

Status of the deletion of an Amazon ES domain. True if deletion of the domain is complete. False if domain deletion is still in progress.

id

same as domainid

arn

Amazon Resource Name (ARN) of an Amazon ES domain.

exposed_internet

exposed_internet is set to True if the ElasticSearch domain has a policy applied to it that makes it internet-accessible. This policy determination is made by using the policyuniverse library. The code for this augmentation is implemented at cartography.intel.aws.elasticsearch._process_access_policy().

+
+

Relationships

+
    +
  • Elastic Search domains can be members of EC2 Security Groups.

    +
    ```
    +(ESDomain)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup)
    +```
    +
    +
    +
  • +
  • Elastic Search domains belong to AWS Accounts.

    +
    (AWSAccount)-[RESOURCE]->(ESDomain)
    +
    +
    +
  • +
  • DNS Records can point to Elastic Search domains.

    +
    ```
    +(DNSRecord)-[DNS_POINTS_TO]->(ESDomain)
    +```
    +
    +
    +
  • +
+
+
+
+

Endpoint

+

Representation of a generic network endpoint.

+ ++++ + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

protocol

The protocol of this endpoint

port

The port of this endpoint

+
+

Relationships

+
    +
  • Endpoints can be installed load balancers, though more specifically we would refer to these Endpoint nodes as ELBListeners.

    +
    ```
    +(LoadBalancer)-[ELB_LISTENER]->(Endpoint)
    +```
    +
    +
    +
  • +
+
+
+
+

Endpoint::ELBListener

+

Representation of an AWS Elastic Load Balancer Listener. Here, an ELBListener is a more specific type of Endpoint. Here’a good introduction.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

protocol

The protocol of this endpoint

port

The port of this endpoint

policy_names

A list of SSL policy names set on the listener.

id

The ELB ID. This is a concatenation of the DNS name, port, and protocol.

instance_port

The port open on the EC2 instance that this listener is connected to

instance_protocol

The protocol defined on the EC2 instance that this listener is connected to

+
+

Relationships

+
    +
  • A ELBListener is installed on a load balancer.

    +
    ```
    +(LoadBalancer)-[ELB_LISTENER]->(ELBListener)
    +```
    +
    +
    +
  • +
+
+
+
+

Endpoint::ELBV2Listener

+

Representation of an AWS Elastic Load Balancer V2 Listener.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

protocol

The protocol of this endpoint - One of 'HTTP''HTTPS''TCP''TLS''UDP''TCP_UDP'

port

The port of this endpoint

ssl_policy

Only set for HTTPS or TLS listener. The security policy that defines which protocols and ciphers are supported.

targetgrouparn

The ARN of the Target Group, if the Action type is forward.

+
+

Relationships

+
    +
  • A ELBV2Listener is installed on a LoadBalancerV2.

    +
    ```
    +(elbv2)-[r:ELBV2_LISTENER]->(ELBV2Listener)
    +```
    +
    +
    +
  • +
+
+
+
+

Ip

+

Represents a generic IP address.

+ ++++ + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

ip

The IPv4 address

id

Same as ip

+
+

Relationships

+
    +
  • DNSRecords can point to IP addresses.

    +
    ```
    +(DNSRecord)-[DNS_POINTS_TO]->(Ip)
    +```
    +
    +
    +
  • +
+
+
+
+

IpRule

+

Represents a generic IP rule. The creation of this node is currently derived from ingesting AWS EC2 Security Group rules.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

ruleid

{group_id}/{rule_type}/{from_port}{to_port}{protocol}

groupid

The groupid of the EC2 Security Group that this was derived from

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

protocol

The protocol this rule applies to

fromport

Lowest port in the range defined by this rule

toport

Highest port in the range defined by this rule

+
+

Relationships

+
    +
  • IpRules are defined from EC2SecurityGroups.

    +
    ```
    +(IpRule, IpPermissionInbound)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup)
    +```
    +
    +
    +
  • +
+
+
+
+

IpRule::IpPermissionInbound

+

An IpPermissionInbound node is a specific type of IpRule. It represents a generic inbound IP-based rules. The creation of this node is currently derived from ingesting AWS EC2 Security Group rules.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

ruleid

{group_id}/{rule_type}/{from_port}{to_port}{protocol}

groupid

The groupid of the EC2 Security Group that this was derived from

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

protocol

The protocol this rule applies to

fromport

Lowest port in the range defined by this rule

toport

Highest port in the range defined by this rule

+
+

Relationships

+
    +
  • IpPermissionInbound rules are defined from EC2SecurityGroups.

    +
    ```
    +(IpRule, IpPermissionInbound)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup)
    +```
    +
    +
    +
  • +
+
+
+
+

LoadBalancer

+

Represents an AWS Elastic Load Balancer. See spec for details.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

scheme

The type of load balancer. Valid only for load balancers in a VPC. If scheme is internet-facing, the load balancer has a public DNS name that resolves to a public IP address. If scheme is internal, the load balancer has a public DNS name that resolves to a private IP address.

name

The name of the load balancer

dnsname

The DNS name of the load balancer.

canonicalhostedzonename

The DNS name of the load balancer

id

Currently set to the dnsname of the load balancer.

region

The region of the load balancer

createdtime

The date and time the load balancer was created.

canonicalhostedzonenameid

The ID of the Amazon Route 53 hosted zone for the load balancer.

exposed_internet

The exposed_internet flag is set to True when the load balancer’s scheme field is set to internet-facing. This indicates that the load balancer has a public DNS name that resolves to a public IP address.

+
+

Relationships

+
    +
  • LoadBalancers can be connected to EC2Instances and therefore expose them.

    +
    ```
    +(LoadBalancer)-[EXPOSE]->(EC2Instance)
    +```
    +
    +
    +
  • +
  • LoadBalancers can have source security groups configured.

    +
    ```
    +(LoadBalancer)-[SOURCE_SECURITY_GROUP]->(EC2SecurityGroup)
    +```
    +
    +
    +
  • +
  • LoadBalancers can be part of EC2SecurityGroups.

    +
    ```
    +(LoadBalancer)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup)
    +```
    +
    +
    +
  • +
  • LoadBalancers can be part of EC2 Subnets

    +
    ```
    +(LoadBalancer)-[SUBNET]->(EC2Subnet)
    +```
    +
    +
    +
  • +
  • LoadBalancers can be part of EC2 Subnets

    +
    ```
    +(LoadBalancer)-[PART_OF_SUBNET]->(EC2Subnet)
    +```
    +
    +
    +
  • +
  • LoadBalancers can have listeners configured to accept connections from clients (good introduction).

    +
    ```
    +(LoadBalancer)-[ELB_LISTENER]->(Endpoint, ELBListener)
    +```
    +
    +
    +
  • +
  • LoadBalancers are part of AWSAccounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(LoadBalancer)
    +```
    +
    +
    +
  • +
  • AWSDNSRecords and DNSRecords point to LoadBalancers.

    +
    ```
    +(AWSDNSRecord, DNSRecord)-[DNS_POINTS_TO]->(LoadBalancer)
    +```
    +
    +
    +
  • +
+
+
+
+

LoadBalancerV2

+

Represents an Elastic Load Balancer V2 (Application Load Balancer or Network Load Balancer.) API reference here.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

scheme

The type of load balancer. If scheme is internet-facing, the load balancer has a public DNS name that resolves to a public IP address. If scheme is internal, the load balancer has a public DNS name that resolves to a private IP address.

name

The name of the load balancer

dnsname

The DNS name of the load balancer.

exposed_internet

The exposed_internet flag is set to True when the load balancer’s scheme field is set to internet-facing. This indicates that the load balancer has a public DNS name that resolves to a public IP address.

id

Currently set to the dnsname of the load balancer.

type

Can be application or network

region

The region of the load balancer

createdtime

The date and time the load balancer was created.

canonicalhostedzonenameid

The ID of the Amazon Route 53 hosted zone for the load balancer.

+
+

Relationships

+
    +
  • LoadBalancerV2’s can be connected to EC2Instances and therefore expose them.

    +
    ```
    +(LoadBalancerV2)-[EXPOSE]->(EC2Instance)
    +```
    +
    +
    +
  • +
  • LoadBalancerV2’s can be part of EC2SecurityGroups but only if their type = “application”. NLBs don’t have SGs.

    +
    ```
    +(LoadBalancerV2)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup)
    +```
    +
    +
    +
  • +
  • LoadBalancerV2’s can be part of EC2 Subnets

    +
    ```
    +(LoadBalancerV2)-[SUBNET]->(EC2Subnet)
    +```
    +
    +
    +
  • +
  • LoadBalancerV2’s can be part of EC2 Subnets

    +
    ```
    +(LoadBalancerV2)-[PART_OF_SUBNET]->(EC2Subnet)
    +```
    +
    +
    +
  • +
  • LoadBalancerV2’s have listeners:

    +
    ```
    +(LoadBalancerV2)-[ELBV2_LISTENER]->(ELBV2Listener)
    +```
    +
    +
    +
  • +
+
+
+
+

Nameserver

+

Represents a DNS nameserver. +| Field | Description | +|-------|————-| +| firstseen| Timestamp of when a sync job first discovered this node | +| lastupdated | Timestamp of the last time the node was updated | +| id | The address of the nameserver| +| name | The name or address of the nameserver|

+
+

Relationships

+
    +
  • Nameservers are nameservers for to DNSZone.

    +
    ```
    +(Nameserver)-[NAMESERVER]->(DNSZone)
    +```
    +
    +
    +
  • +
+
+
+
+

NetworkInterface

+

Representation of a generic Network Interface. Currently however, we only create NetworkInterface nodes from AWS EC2 Instances. The spec for an AWS EC2 network interface is here.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

mac_address

The MAC address of the network interface

description

Description of the network interface

private_ip_address

The primary IPv4 address of the network interface within the subnet

id

The ID of the network interface. (known as networkInterfaceId in EC2)

private_dns_name

The private DNS name

status

Status of the network interface. Valid Values: available | associated | attaching | in-use | detaching

subnetid

The ID of the subnet

interface_type

Describes the type of network interface. Valid values: interface | efa

requester_id

Id of the requester, e.g. amazon-elb for ELBs

requester_managed

Indicates whether the interface is managed by the requester

source_dest_check

Indicates whether to validate network traffic to or from this network interface.

public_ip

Public IPv4 address attached to the interface

+
+

Relationships

+
    +
  • EC2 Network Interfaces belong to AWS accounts.

    +
    (NetworkInterface)<-[:RESOURCE]->(:AWSAccount)
    +
    +
    +
  • +
  • Network interfaces can be connected to EC2Subnets.

    +
    ```
    +(NetworkInterface)-[PART_OF_SUBNET]->(EC2Subnet)
    +```
    +
    +
    +
  • +
  • Network interfaces can be members of EC2SecurityGroups.

    +
    ```
    +(NetworkInterface)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup)
    +```
    +
    +
    +
  • +
  • EC2Instances can have NetworkInterfaces connected to them.

    +
    ```
    +(EC2Instance)-[NETWORK_INTERFACE]->(NetworkInterface)
    +```
    +
    +
    +
  • +
  • LoadBalancers can have NetworkInterfaces connected to them.

    +
    ```
    +(LoadBalancer)-[NETWORK_INTERFACE]->(NetworkInterface)
    +```
    +
    +
    +
  • +
  • LoadBalancerV2s can have NetworkInterfaces connected to them.

    +
    ```
    +(LoadBalancerV2)-[NETWORK_INTERFACE]->(NetworkInterface)
    +```
    +
    +
    +
  • +
  • EC2PrivateIps are connected to a NetworkInterface.

    +
    ```
    +(NetworkInterface)-[PRIVATE_IP_ADDRESS]->(EC2PrivateIp)
    +```
    +
    +
    +
  • +
  • EC2 Network Interfaces can be tagged with AWSTags.

    +
    ```
    +(NetworkInterface)-[TAGGED]->(AWSTag)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSPeeringConnection

+

Representation of an AWS PeeringConnection implementing an AWS VpcPeeringConnection object.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

vpcPeeringConnectionId, The ID of the VPC peering connection.

allow_dns_resolution_from_remote_vpc

Indicates whether a local VPC can resolve public DNS hostnames to private IP addresses when queried from instances in a peer VPC.

allow_egress_from_local_classic_link_to_remote_vpc

Indicates whether a local ClassicLink connection can communicate with the peer VPC over the VPC peering connection.

allow_egress_from_local_vpc_to_remote_classic_link

Indicates whether a local VPC can communicate with a ClassicLink connection in the peer VPC over the VPC peering connection.

requester_region

Peering requester region

accepter_region

Peering accepter region

status_code

The status of the VPC peering connection.

status_message

A message that provides more information about the status, if applicable.

+
+

Relationships

+
    +
  • AWSVpc is an accepter or requester vpc.

    +
    (AWSVpc)<-[REQUESTER_VPC]-(AWSPeeringConnection)
    +(AWSVpc)<-[ACCEPTER_VPC]-(AWSPeeringConnection)
    +
    +
    +
  • +
  • AWSCidrBlock is an accepter or requester cidr.

    +
    (AWSCidrBlock)<-[REQUESTER_CIDR]-(AWSPeeringConnection)
    +(AWSCidrBlock)<-[ACCEPTER_CIDR]-(AWSPeeringConnection)
    +
    +
    +
  • +
+
+
+
+

RedshiftCluster

+

Representation of an AWS RedshiftCluster.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

arn

The Amazon Resource Name (ARN) for the Redshift cluster

id

Same as arn

availability_zone

Specifies the name of the Availability Zone the cluster is located in

cluster_create_time

Provides the date and time the cluster was created

cluster_identifier

The unique identifier of the cluster.

cluster_revision_number

The specific revision number of the database in the cluster.

db_name

The name of the initial database that was created when the cluster was created. This same name is returned for the life of the cluster. If an initial database was not specified, a database named devdev was created by default.

encrypted

Specifies whether the cluster has encryption enabled

cluster_status

The current state of the cluster.

endpoint_address

DNS name of the Redshift cluster endpoint

endpoint_port

The port that the Redshift cluster’s endpoint is listening on

master_username

The master user name for the cluster. This name is used to connect to the database that is specified in the DBName parameter.

node_type

The node type for the nodes in the cluster.

number_of_nodes

The number of compute nodes in the cluster.

publicly_accessible

A boolean value that, if true, indicates that the cluster can be accessed from a public network.

vpc_id

The identifier of the VPC the cluster is in, if the cluster is in a VPC.

+
+

Relationships

+
    +
  • Redshift clusters are part of AWS Accounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(RedshiftCluster)
    +```
    +
    +
    +
  • +
  • Redshift clusters can be members of EC2 Security Groups.

    +
    (RedshiftCluster)-[MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup)
    +
    +
    +
  • +
  • Redshift clusters may assume IAM roles. See this article.

    +
    (RedshiftCluster)-[STS_ASSUMEROLE_ALLOW]->(AWSPrincipal)
    +
    +
    +
  • +
  • Redshift clusters can be members of AWSVpcs.

    +
    (RedshiftCluster)-[MEMBER_OF_AWS_VPC]->(AWSVpc)
    +
    +
    +
  • +
+
+
+
+

RDSCluster

+

Representation of an AWS Relational Database Service DBCluster

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Same as ARN

arn

The Amazon Resource Name (ARN) for the DB cluster.

allocated_storage

For all database engines except Amazon Aurora, AllocatedStorage specifies the allocated storage size in gibibytes (GiB). For Aurora, AllocatedStorage always returns 1, because Aurora DB cluster storage size isn’t fixed, but instead automatically adjusts as needed.

availability_zones

Provides the list of Availability Zones (AZs) where instances in the DB cluster can be created.

backup_retention_period

Specifies the number of days for which automatic DB snapshots are retained.

character_set_name

If present, specifies the name of the character set that this cluster is associated with.

database_name

Contains the name of the initial database of this DB cluster that was provided at create time, if one was specified when the DB cluster was created. This same name is returned for the life of the DB cluster.

db_cluster_identifier

Contains a user-supplied DB cluster identifier. This identifier is the unique key that identifies a DB cluster.

db_parameter_group

Specifies the name of the DB cluster parameter group for the DB cluster.

status

Specifies the current state of this DB cluster.

earliest_restorable_time

The earliest time to which a database can be restored with point-in-time restore.

endpoint

Specifies the connection endpoint for the primary instance of the DB cluster.

reader_endpoint

The reader endpoint for the DB cluster. The reader endpoint for a DB cluster load-balances connections across the Aurora Replicas that are available in a DB cluster. As clients request new connections to the reader endpoint, Aurora distributes the connection requests among the Aurora Replicas in the DB cluster. This functionality can help balance your read workload across multiple Aurora Replicas in your DB cluster. If a failover occurs, and the Aurora Replica that you are connected to is promoted to be the primary instance, your connection is dropped. To continue sending your read workload to other Aurora Replicas in the cluster, you can then reconnect to the reader endpoint.

multi_az

Specifies whether the DB cluster has instances in multiple Availability Zones.

engine

The name of the database engine to be used for this DB cluster.

engine_version

Indicates the database engine version.

latest_restorable_time

Specifies the latest time to which a database can be restored with point-in-time restore.

port

Specifies the port that the database engine is listening on.

master_username

Contains the master username for the DB cluster.

preferred_backup_window

Specifies the daily time range during which automated backups are created if automated backups are enabled, as determined by the BackupRetentionPeriod.

preferred_maintenance_window

Specifies the weekly time range during which system maintenance can occur, in Universal Coordinated Time (UTC).

hosted_zone_id

Specifies the ID that Amazon Route 53 assigns when you create a hosted zone.

storage_encrypted

Specifies whether the DB cluster is encrypted.

kms_key_id

If StorageEncrypted is enabled, the AWS KMS key identifier for the encrypted DB cluster. The AWS KMS key identifier is the key ARN, key ID, alias ARN, or alias name for the AWS KMS customer master key (CMK).

db_cluster_resource_id

The AWS Region-unique, immutable identifier for the DB cluster. This identifier is found in AWS CloudTrail log entries whenever the AWS KMS CMK for the DB cluster is accessed.

clone_group_id

Identifies the clone group to which the DB cluster is associated.

cluster_create_time

Specifies the time when the DB cluster was created, in Universal Coordinated Time (UTC).

earliest_backtrack_time

The earliest time to which a DB cluster can be backtracked.

backtrack_window

The target backtrack window, in seconds. If this value is set to 0, backtracking is disabled for the DB cluster. Otherwise, backtracking is enabled.

backtrack_consumed_change_records

The number of change records stored for Backtrack.

capacity

The current capacity of an Aurora Serverless DB cluster. The capacity is 0 (zero) when the cluster is paused.

engine_mode

The DB engine mode of the DB cluster, either provisioned, serverless, parallelquery, global, or multimaster.

scaling_configuration_info_min_capacity

The minimum capacity for the Aurora DB cluster in serverless DB engine mode.

scaling_configuration_info_max_capacity

The maximum capacity for an Aurora DB cluster in serverless DB engine mode.

scaling_configuration_info_auto_pause

A value that indicates whether automatic pause is allowed for the Aurora DB cluster in serverless DB engine mode.

deletion_protection

Indicates if the DB cluster has deletion protection enabled. The database can’t be deleted when deletion protection is enabled.

+
+

Relationships

+
    +
  • RDS Clusters are part of AWS Accounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(RDSCluster)
    +```
    +
    +
    +
  • +
  • Some RDS instances are cluster members.

    +
    (replica:RDSInstance)-[IS_CLUSTER_MEMBER_OF]->(source:RDSCluster)
    +
    +
    +
  • +
+
+
+
+

RDSInstance

+

Representation of an AWS Relational Database Service DBInstance.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Same as ARN

arn

The Amazon Resource Name (ARN) for the DB instance.

db_instance_identifier

Contains a user-supplied database identifier. This identifier is the unique key that identifies a DB instance.

availability_zone

Specifies the name of the Availability Zone the DB instance is located in.

backup_retention_period

Specifies the number of days for which automatic DB snapshots are retained.

preferred_backup_window

Specifies the daily time range during which automated backups are created if automated backups are enabled, as determined by the BackupRetentionPeriod.

ca_certificate_identifier

The identifier of the CA certificate for this DB instance.

db_cluster_identifier

If the DB instance is a member of a DB cluster, contains the name of the DB cluster that the DB instance is a member of.

db_instance_class

Contains the name of the compute and memory capacity class of the DB instance.

db_instance_port

Specifies the port that the DB instance listens on.

dbi_resource_id

The AWS Region-unique, immutable identifier for the DB instance. This identifier is found in AWS CloudTrail log entries whenever the AWS KMS key for the DB instance is accessed.

db_name

The meaning of this parameter differs according to the database engine you use. For example, this value returns MySQL, MariaDB, or PostgreSQL information when returning values from CreateDBInstanceReadReplica since Read Replicas are only supported for these engines.

MySQL, MariaDB, SQL Server, PostgreSQL: Contains the name of the initial database of this instance that was provided at create time, if one was specified when the DB instance was created. This same name is returned for the life of the DB instance.

Oracle: Contains the Oracle System ID (SID) of the created DB instance. Not shown when the returned parameters do not apply to an Oracle DB instance.

engine

Provides the name of the database engine to be used for this DB instance.

engine_version

Indicates the database engine version.

enhanced_monitoring_resource_arn

The Amazon Resource Name (ARN) of the Amazon CloudWatch Logs log stream that receives the Enhanced Monitoring metrics data for the DB instance.

instance_create_time

Provides the date and time the DB instance was created.

kms_key_id

If StorageEncrypted is true, the AWS KMS key identifier for the encrypted DB instance.

master_username

Contains the master username for the DB instance.

monitoring_role_arn

The ARN for the IAM role that permits RDS to send Enhanced Monitoring metrics to Amazon CloudWatch Logs.

multi_az

Specifies if the DB instance is a Multi-AZ deployment.

performance_insights_enabled

True if Performance Insights is enabled for the DB instance, and otherwise false.

preferred_maintenance_window

Specifies the weekly time range during which system maintenance can occur, in Universal Coordinated Time (UTC).

publicly_accessible

Specifies the accessibility options for the DB instance. A value of true specifies an Internet-facing instance with a publicly resolvable DNS name, which resolves to a public IP address. A value of false specifies an internal instance with a DNS name that resolves to a private IP address.

storage_encrypted

Specifies whether the DB instance is encrypted.

endpoint_address

DNS name of the RDS instance

endpoint_port

The port that the RDS instance is listening on

endpoint_hostedzoneid

The AWS DNS Zone ID that is associated with the RDS instance’s DNS entry

auto_minor_version_upgrade

Specifies whether minor version upgrades are applied automatically to the DB instance during the maintenance window

iam_database_authentication_enabled

Specifies if mapping of AWS Identity and Access Management (IAM) accounts to database accounts is enabled

+
+

Relationships

+
    +
  • RDS Instances are part of AWS Accounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(RDSInstance)
    +```
    +
    +
    +
  • +
  • Some RDS instances are Read Replicas.

    +
    (replica:RDSInstance)-[IS_READ_REPLICA_OF]->(source:RDSInstance)
    +
    +
    +
  • +
  • RDS Instances can be members of EC2 Security Groups.

    +
    (RDSInstance)-[m:MEMBER_OF_EC2_SECURITY_GROUP]->(EC2SecurityGroup)
    +
    +
    +
  • +
  • RDS Instances are connected to DB Subnet Groups.

    +
    (RDSInstance)-[:MEMBER_OF_DB_SUBNET_GROUP]->(DBSubnetGroup)
    +
    +
    +
  • +
  • RDS Instances can be tagged with AWSTags.

    +
    ```
    +(RDSInstance)-[TAGGED]->(AWSTag)
    +```
    +
    +
    +
  • +
+
+
+
+

RDSSnapshot

+

Representation of an AWS Relational Database Service DBSnapshot.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Same as ARN

arn

The Amazon Resource Name (ARN) for the DB snapshot.

db_snapshot_identifier

Specifies the identifier for the DB snapshot.

db_instance_identifier

Specifies the DB instance identifier of the DB instance this DB snapshot was created from.

snapshot_create_time

Specifies when the snapshot was taken in Coordinated Universal Time (UTC). Changes for the copy when the snapshot is copied.

engine

Specifies the name of the database engine.

allocated_storage

Specifies the allocated storage size in gibibytes (GiB).

status

Specifies the status of this DB snapshot.

port

Specifies the port that the database engine was listening on at the time of the snapshot.

availability_zone

Specifies the name of the Availability Zone the DB instance was located in at the time of the DB snapshot.

vpc_id

Provides the VPC ID associated with the DB snapshot.

instance_create_time

Specifies the time in Coordinated Universal Time (UTC) when the DB instance, from which the snapshot was taken, was created.

master_username

Provides the master username for the DB snapshot.

engine_version

Specifies the version of the database engine.

license_model

License model information for the restored DB instance.

snapshot_type

Provides the type of the DB snapshot.

iops

Specifies the Provisioned IOPS (I/O operations per second) value of the DB instance at the time of the snapshot.

option_group_name

Provides the option group name for the DB snapshot.

percent_progress

The percentage of the estimated data that has been transferred.

source_region

The AWS Region that the DB snapshot was created in or copied from.

source_db_snapshot_identifier

The DB snapshot Amazon Resource Name (ARN) that the DB snapshot was copied from. It only has a value in the case of a cross-account or cross-Region copy.

storage_type

Specifies the storage type associated with DB snapshot.

tde_credential_arn

The ARN from the key store with which to associate the instance for TDE encryption.

encrypted

Specifies whether the DB snapshot is encrypted.

kms_key_id

If Encrypted is true, the AWS KMS key identifier for the encrypted DB snapshot. The AWS KMS key identifier is the key ARN, key ID, alias ARN, or alias name for the KMS key.

timezone

The time zone of the DB snapshot. In most cases, the Timezone element is empty. Timezone content appears only for snapshots taken from Microsoft SQL Server DB instances that were created with a time zone specified.

iam_database_authentication_enabled

True if mapping of AWS Identity and Access Management (IAM) accounts to database accounts is enabled, and otherwise false.

processor_features

The number of CPU cores and the number of threads per core for the DB instance class of the DB instance when the DB snapshot was created.

dbi_resource_id

The identifier for the source DB instance, which can’t be changed and which is unique to an AWS Region.

original_snapshot_create_time

Specifies the time of the CreateDBSnapshot operation in Coordinated Universal Time (UTC). Doesn’t change when the snapshot is copied.

snapshot_database_time

The timestamp of the most recent transaction applied to the database that you’re backing up. Thus, if you restore a snapshot, SnapshotDatabaseTime is the most recent transaction in the restored DB instance. In contrast, originalSnapshotCreateTime specifies the system time that the snapshot completed. If you back up a read replica, you can determine the replica lag by comparing SnapshotDatabaseTime with originalSnapshotCreateTime. For example, if originalSnapshotCreateTime is two hours later than SnapshotDatabaseTime, then the replica lag is two hours.

snapshot_target

Specifies where manual snapshots are stored: AWS Outposts or the AWS Region.

storage_throughput

region

The AWS region of the snapshot

+
+

Relationships

+
    +
  • RDS Snapshots are part of AWS Accounts.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(RDSSnapshot)
    +```
    +
    +
    +
  • +
  • RDS Snapshots are connected to DB Instances.

    +
    (RDSSnapshot)-[:IS_SNAPSHOT_SOURCE]->(RDSInstance)
    +
    +
    +
  • +
  • RDS Snapshots can be tagged with AWSTags.

    +
    ```
    +(RDSSnapshot)-[TAGGED]->(AWSTag)
    +```
    +
    +
    +
  • +
+
+
+
+

S3Acl

+

Representation of an AWS S3 Access Control List.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

granteeid

The ID of the grantee as defined here

displayname

Optional display name for the ACL

permission

Valid values: FULL_CONTROL | READ | WRITE | READ_ACP | WRITE_ACP (ACP = Access Control Policy)

id

The ID of this ACL

type

The type of the grantee. Either CanonicalUser | AmazonCustomerByEmail | Group.

ownerid

The ACL’s owner ID as defined here

+
+

Relationships

+
    +
  • S3 Access Control Lists apply to S3 buckets.

    +
    ```
    +(S3Acl)-[APPLIES_TO]->(S3Bucket)
    +```
    +
    +
    +
  • +
+
+
+
+

S3Bucket

+

Representation of an AWS S3 Bucket.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

creationdate

Date-time when the bucket was created

id

Same as name, as seen below

name

The name of the bucket. This is guaranteed to be globally unique

anonymous_actions

List of anonymous internet accessible actions that may be run on the bucket. This list is taken by running policyuniverse on the policy that applies to the bucket.

anonymous_access

True if this bucket has a policy applied to it that allows anonymous access or if it is open to the internet. These policy determinations are made by using the policyuniverse library.

region

The region that the bucket is in. Only defined if the S3 bucket has a location constraint

default_encryption

True if this bucket has default encryption enabled.

encryption_algorithm

The encryption algorithm used for default encryption. Only defined if the S3 bucket has default encryption enabled.

encryption_key_id

The KMS key ID used for default encryption. Only defined if the S3 bucket has SSE-KMS enabled as the default encryption method.

bucket_key_enabled

True if a bucket key is enabled, when using SSE-KMS as the default encryption method.

versioning_status

The versioning state of the bucket.

mfa_delete

Specifies whether MFA delete is enabled in the bucket versioning configuration.

block_public_acls

Specifies whether Amazon S3 should block public access control lists (ACLs) for this bucket and objects in this bucket.

ignore_public_acls

Specifies whether Amazon S3 should ignore public ACLs for this bucket and objects in this bucket.

block_public_acls

Specifies whether Amazon S3 should block public bucket policies for this bucket.

restrict_public_buckets

Specifies whether Amazon S3 should restrict public bucket policies for this bucket.

+
+

Relationships

+
    +
  • S3Buckets are resources in an AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(S3Bucket)
    +```
    +
    +
    +
  • +
  • S3 Access Control Lists apply to S3 buckets.

    +
    ```
    +(S3Acl)-[APPLIES_TO]->(S3Bucket)
    +```
    +
    +
    +
  • +
  • S3 Buckets can be tagged with AWSTags.

    +
    ```
    +(S3Bucket)-[TAGGED]->(AWSTag)
    +```
    +
    +
    +
  • +
+
+
+
+

S3PolicyStatement

+

Representation of an AWS S3 Bucket Policy Statements for controlling ownership of objects and ACLs of the bucket.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

policy_id

Optional string “Id” for the bucket’s policy

policy_version

Version of the bucket’s policy

id

The unique identifier for a bucket policy statement.
If the statement has an Sid the id will be calculated as S3Bucket.id/policy_statement/index of statement in statement/Sid.
If the statement has no Sid the id will be calculated as S3Bucket.id/policy_statement/index of statement in statement/

effect

Specifies “Deny” or “Allow” for the policy statement

action

Specifies permissions that policy statement applies to, as defined here

resource

Specifies the resource the bucket policy statement is based on

condition

Specifies conditions where permissions are granted: examples

sid

Optional string to label the specific bucket policy statement

+
+

Relationships

+
    +
  • S3PolicyStatements define the policy for S3 Buckets.

    +
    ```
    +(:S3Bucket)-[:POLICY_STATEMENT]->(:S3PolicyStatement)
    +```
    +
    +
    +
  • +
+
+
+
+

KMSKey

+

Representation of an AWS KMS Key.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The id of the key

name

The name of the key

description

The description of the key

enabled

Whether the key is enabled

region

The region where key is created

anonymous_actions

List of anonymous internet accessible actions that may be run on the key.

anonymous_access

True if this key has a policy applied to it that allows anonymous access or if it is open to the internet.

+
+

Relationships

+
    +
  • AWS KMS Keys are resources in an AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(KMSKey)
    +```
    +
    +
    +
  • +
  • AWS KMS Key may also be refered as KMSAlias via aliases.

    +
    ```
    +(KMSKey)-[KNOWN_AS]->(KMSAlias)
    +```
    +
    +
    +
  • +
  • AWS KMS Key may also have KMSGrant based on grants.

    +
    ```
    +(KMSGrant)-[APPLIED_ON]->(KMSKey)
    +```
    +
    +
    +
  • +
+
+
+
+

KMSAlias

+

Representation of an AWS KMS Key Alias.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The arn of the alias

aliasname

The name of the alias

targetkeyid

The kms key id associated via this alias

+
+

Relationships

+
    +
  • AWS KMS Key may also be refered as KMSAlias via aliases.

    +
    ```
    +(KMSKey)-[KNOWN_AS]->(KMSAlias)
    +```
    +
    +
    +
  • +
+
+
+
+

KMSGrant

+

Representation of an AWS KMS Key Grant.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The id of the key grant

name

The name of the key grant

granteeprincipal

The principal associated with the key grant

creationdate

ISO 8601 date-time string when the grant was created

+
+

Relationships

+
    +
  • AWS KMS Key may also have KMSGrant based on grants.

    +
    ```
    +(KMSGrant)-[APPLIED_ON]->(KMSKey)
    +```
    +
    +
    +
  • +
+
+
+
+

APIGatewayRestAPI

+

Representation of an AWS API Gateway REST API.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The id of the REST API

createddate

The timestamp when the REST API was created

version

The version identifier for the API

minimumcompressionsize

A nullable integer that is used to enable or disable the compression of the REST API

disableexecuteapiendpoint

Specifies whether clients can invoke your API by using the default execute-api endpoint

region

The region where the REST API is created

anonymous_actions

List of anonymous internet accessible actions that may be run on the API.

anonymous_access

True if this API has a policy applied to it that allows anonymous access or if it is open to the internet.

+
+

Relationships

+
    +
  • AWS API Gateway REST APIs are resources in an AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(APIGatewayRestAPI)
    +```
    +
    +
    +
  • +
  • AWS API Gateway REST APIs may be associated with an API Gateway Stage.

    +
    ```
    +(APIGatewayRestAPI)-[ASSOCIATED_WITH]->(APIGatewayStage)
    +```
    +
    +
    +
  • +
  • AWS API Gateway REST APIs may also have API Gateway Resource resources.

    +
    ```
    +(APIGatewayRestAPI)-[RESOURCE]->(APIGatewayResource)
    +```
    +
    +
    +
  • +
+
+
+
+

APIGatewayStage

+

Representation of an AWS API Gateway Stage.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The name of the API Gateway Stage

createddate

The timestamp when the stage was created

deploymentid

The identifier of the Deployment that the stage points to.

clientcertificateid

The identifier of a client certificate for an API stage.

cacheclusterenabled

Specifies whether a cache cluster is enabled for the stage.

cacheclusterstatus

The status of the cache cluster for the stage, if enabled.

tracingenabled

Specifies whether active tracing with X-ray is enabled for the Stage

webaclarn

The ARN of the WebAcl associated with the Stage

+
+

Relationships

+
    +
  • AWS API Gateway REST APIs may be associated with an API Gateway Stage.

    +
    ```
    +(APIGatewayRestAPI)-[ASSOCIATED_WITH]->(APIGatewayStage)
    +```
    +
    +
    +
  • +
  • AWS API Gateway Stage may also contain a Client Certificate.

    +
    ```
    +(APIGatewayStage)-[HAS_CERTIFICATE]->(APIGatewayClientCertificate)
    +```
    +
    +
    +
  • +
+
+
+
+

APIGatewayClientCertificate

+

Representation of an AWS API Gateway Client Certificate.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The identifier of the client certificate

createddate

The timestamp when the client certificate was created

expirationdate

The timestamp when the client certificate will expire

+
+

Relationships

+
    +
  • AWS API Gateway Stage may also contain a Client Certificate.

    +
    ```
    +(APIGatewayStage)-[HAS_CERTIFICATE]->(APIGatewayClientCertificate)
    +```
    +
    +
    +
  • +
+
+
+
+

APIGatewayResource

+

Representation of an AWS API Gateway Resource.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The id of the REST API

path

The timestamp when the REST API was created

pathpart

The version identifier for the API

parentid

A nullable integer that is used to enable or disable the compression of the REST API

+
+

Relationships

+
    +
  • AWS API Gateway REST APIs may also have API Gateway Resource resources.

    +
    ```
    +(APIGatewayRestAPI)-[RESOURCE]->(APIGatewayResource)
    +```
    +
    +
    +
  • +
+
+
+
+

AutoScalingGroup

+

Representation of an AWS Auto Scaling Group Resource.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

arn

The ARN of the Auto Scaling Group

name

The name of the Auto Scaling group.

createdtime

The date and time the group was created.

launchconfigurationname

The name of the associated launch configuration.

launchtemplatename

The name of the launch template.

launchtemplateid

The ID of the launch template.

launchtemplateversion

The version number of the launch template.

maxsize

The maximum size of the group.

minsize

The minimum size of the group.

defaultcooldown

The duration of the default cooldown period, in seconds.

desiredcapacity

The desired size of the group.

healthchecktype

The service to use for the health checks.

healthcheckgraceperiod

The amount of time, in seconds, that Amazon EC2 Auto Scaling waits before checking the health status of an EC2 instance that has come into service.

status

The current state of the group when the DeleteAutoScalingGroup operation is in progress.

newinstancesprotectedfromscalein

Indicates whether newly launched instances are protected from termination by Amazon EC2 Auto Scaling when scaling in.

maxinstancelifetime

The maximum amount of time, in seconds, that an instance can be in service.

capacityrebalance

Indicates whether Capacity Rebalancing is enabled.

region

The region of the auto scaling group.

+

Link to API Documentation of AWS Auto Scaling Groups

+
+

Relationships

+
    +
  • AWS Auto Scaling Groups are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AutoScalingGroup)
    +```
    +
    +
    +
  • +
  • AWS Auto Scaling Groups has one or more subnets/vpc identifiers.

    +
    ```
    +(AutoScalingGroup)-[VPC_IDENTIFIER]->(EC2Subnet)
    +```
    +
    +
    +
  • +
  • AWS EC2 Instances are members of one or more AWS Auto Scaling Groups.

    +
    ```
    +(EC2Instance)-[MEMBER_AUTO_SCALE_GROUP]->(AutoScalingGroup)
    +```
    +
    +
    +
  • +
  • AWS Auto Scaling Groups have Launch Configurations

    +
    ```
    +(AutoScalingGroup)-[HAS_LAUNCH_CONFIG]->(LaunchConfiguration)
    +```
    +
    +
    +
  • +
  • AWS Auto Scaling Groups have Launch Templates

    +
    ```
    +(AutoScalingGroup)-[HAS_LAUNCH_TEMPLATE]->(LaunchTemplate)
    +```
    +
    +
    +
  • +
+
+
+
+

EC2Image

+

Representation of an AWS EC2 Images (AMIs).

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the AMI.

name

The name of the AMI that was provided during image creation.

creationdate

The date and time the image was created.

architecture

The architecture of the image.

location

The location of the AMI.

type

The type of image.

ispublic

Indicates whether the image has public launch permissions.

platform

This value is set to windows for Windows AMIs; otherwise, it is blank.

usageoperation

The operation of the Amazon EC2 instance and the billing code that is associated with the AMI.

state

The current state of the AMI.

description

The description of the AMI that was provided during image creation.

enasupport

Specifies whether enhanced networking with ENA is enabled.

hypervisor

The hypervisor type of the image.

rootdevicename

The device name of the root device volume (for example, /dev/sda1 ).

rootdevicetype

The type of root device used by the AMI.

virtualizationtype

The type of virtualization of the AMI.

bootmode

The boot mode of the image.

region

The region of the image.

+

Link to API Documentation of EC2 Images

+
+

Relationships

+
    +
  • AWS EC2 Images (AMIs) are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(EC2Image)
    +```
    +
    +
    +
  • +
+
+
+
+

EC2ReservedInstance

+

Representation of an AWS EC2 Reserved Instance.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the Reserved Instance.

availabilityzone

The Availability Zone in which the Reserved Instance can be used.

duration

The duration of the Reserved Instance, in seconds.

end

The time when the Reserved Instance expires.

start

The date and time the Reserved Instance started.

count

The number of reservations purchased.

type

The instance type on which the Reserved Instance can be used.

productdescription

The Reserved Instance product platform description.

state

The state of the Reserved Instance purchase.

currencycode

The currency of the Reserved Instance. It’s specified using ISO 4217 standard currency codes.

instancetenancy

The tenancy of the instance.

offeringclass

The offering class of the Reserved Instance.

offeringtype

The Reserved Instance offering type.

scope

The scope of the Reserved Instance.

fixedprice

The purchase price of the Reserved Instance.

region

The region of the reserved instance.

+
+

Relationships

+
    +
  • AWS EC2 Reserved Instances are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(EC2ReservedInstance)
    +```
    +
    +
    +
  • +
+
+
+
+

SecretsManagerSecret

+

Representation of an AWS Secrets Manager Secret

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The arn of the secret.

created_date

The date and time when a secret was created.

deleted_date

The date and time the deletion of the secret occurred. Not present on active secrets. The secret can be recovered until the number of days in the recovery window has passed, as specified in the RecoveryWindowInDays parameter of the DeleteSecret operation.

description

The user-provided description of the secret.

kms_key_id

The ARN or alias of the AWS KMS customer master key (CMK) used to encrypt the SecretString and SecretBinary fields in each version of the secret. If you don’t provide a key, then Secrets Manager defaults to encrypting the secret fields with the default KMS CMK, the key named awssecretsmanager, for this account.

last_accessed_date

The last date that this secret was accessed. This value is truncated to midnight of the date and therefore shows only the date, not the time.

last_changed_date

The last date and time that this secret was modified in any way.

last_rotated_date

The most recent date and time that the Secrets Manager rotation process was successfully completed. This value is null if the secret hasn’t ever rotated.

name

The friendly name of the secret. You can use forward slashes in the name to represent a path hierarchy. For example, /prod/databases/dbserver1 could represent the secret for a server named dbserver1 in the folder databases in the folder prod.

owning_service

Returns the name of the service that created the secret.

primary_region

The Region where Secrets Manager originated the secret.

rotation_enabled

Indicates whether automatic, scheduled rotation is enabled for this secret.

rotation_lambda_arn

The ARN of an AWS Lambda function invoked by Secrets Manager to rotate and expire the secret either automatically per the schedule or manually by a call to RotateSecret.

rotation_rules_automatically_after_days

Specifies the number of days between automatic scheduled rotations of the secret.

+
+

Relationships

+
    +
  • AWS Secrets Manager Secrets are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(SecretsManagerSecret)
    +```
    +
    +
    +
  • +
+
+
+
+

EBSVolume

+

Representation of an AWS EBS Volume.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the EBS Volume.

availabilityzone

The Availability Zone for the volume.

createtime

The time stamp when volume creation was initiated.

encrypted

Indicates whether the volume is encrypted.

size

The size of the volume, in GiBs.

state

The volume state.

outpostarn

The Amazon Resource Name (ARN) of the Outpost.

snapshotid

The snapshot ID.

iops

The number of I/O operations per second (IOPS).

type

The volume type.

fastrestored

Indicates whether the volume was created using fast snapshot restore.

multiattachenabled

Indicates whether Amazon EBS Multi-Attach is enabled.

throughput

The throughput that the volume supports, in MiB/s.

kmskeyid

The Amazon Resource Name (ARN) of the AWS Key Management Service (AWS KMS) customer master key (CMK) that was used to protect the volume encryption key for the volume.

deleteontermination

Indicates whether the volume is deleted on instance termination.

region

The region of the volume.

+
+

Relationships

+
    +
  • AWS EBS Volumes are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(EBSVolume)
    +```
    +
    +
    +
  • +
  • AWS EBS Snapshots are created using EBS Volumes

    +
    ```
    +(EBSSnapshot)-[CREATED_FROM]->(EBSVolume)
    +```
    +
    +
    +
  • +
  • AWS EBS Volumes are attached to an EC2 Instance

    +
    ```
    +(EBSVolume)-[ATTACHED_TO_EC2_INSTANCE]->(EC2Instance)
    +```
    +
    +
    +
  • +
  • AWSTag

    +
    ```
    +(EBSVolume)-[TAGGED]->(AWSTag)
    +```
    +
    +
    +
  • +
+
+
+
+

EBSSnapshot

+

Representation of an AWS EBS Snapshot.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the EBS Snapshot.

description

The description of the snapshot.

progress

The progress of the snapshot, as a percentage.

encrypted

Indicates whether the snapshot is encrypted.

starttime

The time stamp when the snapshot was initiated.

state

The snapshot state.

statemessage

Encrypted Amazon EBS snapshots are copied asynchronously. If a snapshot copy operation fails (for example, if the proper AWS Key Management Service (AWS KMS) permissions are not obtained) this field displays error state details to help you diagnose why the error occurred. This parameter is only returned by DescribeSnapshots .

volumeid

The volume ID.

volumesize

The size of the volume, in GiB.

outpostarn

The ARN of the AWS Outpost on which the snapshot is stored.

dataencryptionkeyid

The data encryption key identifier for the snapshot.

kmskeyid

The Amazon Resource Name (ARN) of the AWS Key Management Service (AWS KMS) customer master key (CMK) that was used to protect the volume encryption key for the parent volume.

region

The region of the snapshot.

+
+

Relationships

+
    +
  • AWS EBS Snapshots are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(EBSSnapshot)
    +```
    +
    +
    +
  • +
  • AWS EBS Snapshots are created using EBS Volumes

    +
    ```
    +(EBSSnapshot)-[CREATED_FROM]->(EBSVolume)
    +```
    +
    +
    +
  • +
+
+
+
+

SQSQueue

+

Representation of an AWS SQS Queue

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The arn of the sqs queue.

created_timestamp

The time when the queue was created in seconds

delay_seconds

The default delay on the queue in seconds.

last_modified_timestamp

The time when the queue was last changed in seconds.

maximum_message_size

The limit of how many bytes a message can contain before Amazon SQS rejects it.

message_retention_period

he length of time, in seconds, for which Amazon SQS retains a message.

policy

The IAM policy of the queue.

arn

The arn of the sqs queue.

receive_message_wait_time_seconds

The length of time, in seconds, for which the ReceiveMessage action waits for a message to arrive.

redrive_policy_dead_letter_target_arn

The Amazon Resource Name (ARN) of the dead-letter queue to which Amazon SQS moves messages after the value of maxReceiveCount is exceeded.

redrive_policy_max_receive_count

The number of times a message is delivered to the source queue before being moved to the dead-letter queue. When the ReceiveCount for a message exceeds the maxReceiveCount for a queue, Amazon SQS moves the message to the dead-letter-queue.

visibility_timeout

The visibility timeout for the queue.

kms_master_key_id

The ID of an AWS managed customer master key (CMK) for Amazon SQS or a custom CMK.

kms_data_key_reuse_period_seconds

The length of time, in seconds, for which Amazon SQS can reuse a data key to encrypt or decrypt messages before calling AWS KMS again.

fifo_queue

Whether or not the queue is FIFO.

content_based_deduplication

Whether or not content-based deduplication is enabled for the queue.

deduplication_scope

Specifies whether message deduplication occurs at the message group or queue level.

fifo_throughput_limit

Specifies whether the FIFO queue throughput quota applies to the entire queue or per message group.

+
+

Relationships

+
    +
  • AWS SQS Queues are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(SQSQueue)
    +```
    +
    +
    +
  • +
  • AWS SQS Queues can have other SQS Queues configured as dead letter queues

    +
    ```
    +(SQSQueue)-[HAS_DEADLETTER_QUEUE]->(SQSQueue)
    +```
    +
    +
    +
  • +
+
+
+
+

SecurityHub

+

Representation of the configuration of AWS Security Hub

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The arn of the hub resource.

subscribed_at

The date and time when Security Hub was enabled in the account.

auto_enable_controls

Whether to automatically enable new controls when they are added to standards that are enabled.

+
+

Relationships

+
    +
  • AWS Security Hub nodes are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(SecurityHub)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSConfigurationRecorder

+

Representation of an AWS Config Configuration Recorder

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

A combination of name:account_id:region

name

The name of the recorder.

role_arn

Amazon Resource Name (ARN) of the IAM role used to describe the AWS resources associated with the account.

recording_group_all_supported

Specifies whether AWS Config records configuration changes for every supported type of regional resource.

recording_group_include_global_resource_types

Specifies whether AWS Config includes all supported types of global resources (for example, IAM resources) with the resources that it records.

recording_group_resource_types

A comma-separated list that specifies the types of AWS resources for which AWS Config records configuration changes (for example, AWS::EC2::Instance or AWS::CloudTrail::Trail).

region

The region of the configuration recorder.

+
+

Relationships

+
    +
  • AWS Configuration Recorders are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSConfigurationRecorder)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSConfigDeliveryChannel

+

Representation of an AWS Config Delivery Channel

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

A combination of name:account_id:region

name

The name of the delivery channel.

s3_bucket_name

The name of the Amazon S3 bucket to which AWS Config delivers configuration snapshots and configuration history files.

s3_key_prefix

The prefix for the specified Amazon S3 bucket.

s3_kms_key_arn

The Amazon Resource Name (ARN) of the AWS Key Management Service (KMS) customer managed key (CMK) used to encrypt objects delivered by AWS Config. Must belong to the same Region as the destination S3 bucket.

sns_topic_arn

The Amazon Resource Name (ARN) of the Amazon SNS topic to which AWS Config sends notifications about configuration changes.

config_snapshot_delivery_properties_delivery_frequency

The frequency with which AWS Config delivers configuration snapshots.

region

The region of the delivery channel.

+
+

Relationships

+
    +
  • AWS Config Delivery Channels are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSConfigDeliveryChannel)
    +```
    +
    +
    +
  • +
+
+
+
+

AWSConfigRule

+

Representation of an AWS Config Rule

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ARN of the config rule.

name

The name of the delivery channel.

description

The description that you provide for the AWS Config rule.

arn

The ARN of the config rule.

rule_id

The ID of the AWS Config rule.

scope_compliance_resource_types

The resource types of only those AWS resources that you want to trigger an evaluation for the rule. You can only specify one type if you also specify a resource ID for ComplianceResourceId.

scope_tag_key

The tag key that is applied to only those AWS resources that you want to trigger an evaluation for the rule.

scope_tag_value

The tag value applied to only those AWS resources that you want to trigger an evaluation for the rule. If you specify a value for TagValue, you must also specify a value for TagKey.

scope_tag_compliance_resource_id

The resource types of only those AWS resources that you want to trigger an evaluation for the rule. You can only specify one type if you also specify a resource ID for ComplianceResourceId.

source_owner

Indicates whether AWS or the customer owns and manages the AWS Config rule.

source_identifier

For AWS Config managed rules, a predefined identifier from a list. For example, IAM_PASSWORD_POLICY is a managed rule.

source_details

Provides the source and type of the event that causes AWS Config to evaluate your AWS resources.

input_parameters

A string, in JSON format, that is passed to the AWS Config rule Lambda function.

maximum_execution_frequency

The maximum frequency with which AWS Config runs evaluations for a rule.

created_by

Service principal name of the service that created the rule.

region

The region of the delivery channel.

+
+

Relationships

+
    +
  • AWS Config Rules are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(AWSConfigRule)
    +```
    +
    +
    +
  • +
+
+
+
+

LaunchConfiguration

+

Representation of an AWS Launch Configuration

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ARN of the launch configuration.

name

The name of the launch configuration.

arn

The ARN of the launch configuration.

created_time

The creation date and time for the launch configuration.

image_id

The ID of the Amazon Machine Image (AMI) to use to launch your EC2 instances.

key_name

The name of the key pair.

security_groups

A list that contains the security groups to assign to the instances in the Auto Scaling group.

instance_type

The instance type for the instances.

kernel_id

The ID of the kernel associated with the AMI.

ramdisk_id

The ID of the RAM disk associated with the AMI.

instance_monitoring_enabled

If true, detailed monitoring is enabled. Otherwise, basic monitoring is enabled.

spot_price

The maximum hourly price to be paid for any Spot Instance launched to fulfill the request.

iam_instance_profile

The name or the Amazon Resource Name (ARN) of the instance profile associated with the IAM role for the instance.

ebs_optimized

Specifies whether the launch configuration is optimized for EBS I/O (true) or not (false).

associate_public_ip_address

For Auto Scaling groups that are running in a VPC, specifies whether to assign a public IP address to the group’s instances.

placement_tenancy

The tenancy of the instance, either default or dedicated. An instance with dedicated tenancy runs on isolated, single-tenant hardware and can only be launched into a VPC.

region

The region of the launch configuration.

+
+

Relationships

+
    +
  • Launch Configurations are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(LaunchConfiguration)
    +```
    +
    +
    +
  • +
+
+
+
+

LaunchTemplate

+

Representation of an AWS Launch Template

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the launch template.

name

The name of the launch template.

create_time

The time launch template was created.

created_by

The principal that created the launch template.

default_version_number

The version number of the default version of the launch template.

latest_version_number

The version number of the latest version of the launch template.

region

The region of the launch template.

+
+

Relationships

+
    +
  • Launch Templates are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(LaunchTemplate)
    +```
    +
    +
    +
  • +
  • Launch templates have Launch Template Versions

    +
    ```
    +(LaunchTemplate)-[VERSION]->(LaunchTemplateVersion)
    +```
    +
    +
    +
  • +
+
+
+
+

LaunchTemplateVersion

+

Representation of an AWS Launch Template Version

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the launch template version (ID-version).

name

The name of the launch template.

create_time

The time the version was created.

created_by

The principal that created the version.

default_version

Indicates whether the version is the default version.

version_number

The version number.

version_description

The description of the version.

kernel_id

The ID of the kernel, if applicable.

ebs_optimized

Indicates whether the instance is optimized for Amazon EBS I/O.

iam_instance_profile_arn

The Amazon Resource Name (ARN) of the instance profile.

iam_instance_profile_name

The name of the instance profile.

image_id

The ID of the AMI that was used to launch the instance.

instance_type

The instance type.

key_name

The name of the key pair.

monitoring_enabled

Indicates whether detailed monitoring is enabled. Otherwise, basic monitoring is enabled.

ramdisk_id

The ID of the RAM disk, if applicable.

disable_api_termination

If set to true, indicates that the instance cannot be terminated using the Amazon EC2 console, command line tool, or API.

instance_initiated_shutdown_behavior

Indicates whether an instance stops or terminates when you initiate shutdown from the instance (using the operating system command for system shutdown).

security_group_ids

The security group IDs.

security_groups

The security group names.

region

The region of the launch template.

+
+

Relationships

+
    +
  • Launch Template Versions are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(LaunchTemplateVersion)
    +```
    +
    +
    +
  • +
+
+
+
+

ElasticIPAddress

+

Representation of an AWS EC2 Elastic IP address

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The Elastic IP address

instance_id

The ID of the instance that the address is associated with (if any).

public_ip

The Elastic IP address.

allocation_id

The ID representing the allocation of the address for use with EC2-VPC.

association_id

The ID representing the association of the address with an instance in a VPC.

domain

Indicates whether this Elastic IP address is for use with instances in EC2-Classic (standard) or instances in a VPC (vpc).

network_interface_id

The ID of the network interface.

private_ip_address

The private IP address associated with the Elastic IP address.

public_ipv4_pool

The ID of an address pool.

network_border_group

The name of the unique set of Availability Zones, Local Zones, or Wavelength Zones from which AWS advertises IP addresses.

customer_owned_ip

The customer-owned IP address.

customer_owned_ipv4_pool

The ID of the customer-owned address pool.

carrier_ip

The carrier IP address associated. This option is only available for network interfaces which reside in a subnet in a Wavelength Zone (for example an EC2 instance).

region

The region of the IP.

+
+

Relationships

+
    +
  • Elastic IPs are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(ElasticIPAddress)
    +```
    +
    +
    +
  • +
  • Elastic IPs can be attached to EC2 instances

    +
    ```
    +(EC2Instance)-[ELASTIC_IP_ADDRESS]->(ElasticIPAddress)
    +```
    +
    +
    +
  • +
  • Elastic IPs can be attached to NetworkInterfaces

    +
    ```
    +(NetworkInterface)-[ELASTIC_IP_ADDRESS]->(ElasticIPAddress)
    +```
    +
    +
    +
  • +
+
+
+
+

ECSCluster

+

Representation of an AWS ECS Cluster

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ARN of the cluster

region

The region of the cluster.

name

A user-generated string that you use to identify your cluster.

arn

The ARN of the cluster

ecc_kms_key_id

An AWS Key Management Service key ID to encrypt the data between the local client and the container.

ecc_logging

The log setting to use for redirecting logs for your execute command results.

ecc_log_configuration_cloud_watch_log_group_name

The name of the CloudWatch log group to send logs to.

ecc_log_configuration_cloud_watch_encryption_enabled

Determines whether to enable encryption on the CloudWatch logs.

ecc_log_configuration_s3_bucket_name

The name of the S3 bucket to send logs to.

ecc_log_configuration_s3_encryption_enabled

Determines whether to use encryption on the S3 logs.

ecc_log_configuration_s3_key_prefix

An optional folder in the S3 bucket to place logs in.

status

The status of the cluster

settings_container_insights

If enabled is specified, CloudWatch Container Insights will be enabled for the cluster, otherwise it will be disabled unless the containerInsights account setting is enabled.

capacity_providers

The capacity providers associated with the cluster.

attachments_status

The status of the capacity providers associated with the cluster.

+
+

Relationships

+
    +
  • ECSClusters are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(ECSCluster)
    +```
    +
    +
    +
  • +
+
+
+
+

ECSContainerInstance

+

Representation of an AWS ECS Container Instance

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ARN of the container instance

region

The region of the container instance.

ec2_instance_id

The ID of the container instance. For Amazon EC2 instances, this value is the Amazon EC2 instance ID. For external instances, this value is the AWS Systems Manager managed instance ID.

arn

The ARN of the container instance

capacity_provider_name

The capacity provider that’s associated with the container instance.

version

The version counter for the container instance.

version_info_agent_version

The version number of the Amazon ECS container agent.

version_info_agent_hash

The Git commit hash for the Amazon ECS container agent build on the amazon-ecs-agent GitHub repository.

version_info_agent_docker_version

The Docker version that’s running on the container instance.

status

The status of the container instance.

status_reason

The reason that the container instance reached its current status.

agent_connected

This parameter returns true if the agent is connected to Amazon ECS. Registered instances with an agent that may be unhealthy or stopped return false.

agent_update_status

The status of the most recent agent update. If an update wasn’t ever requested, this value is NULL.

registered_at

The Unix timestamp for the time when the container instance was registered.

+
+

Relationships

+
    +
  • An ECSCluster has ECSContainerInstances

    +
    ```
    +(ECSCluster)-[HAS_CONTAINER_INSTANCE]->(ECSContainerInstance)
    +```
    +
    +
    +
  • +
  • ECSContainerInstances have ECSTasks

    +
    ```
    +(ECSContainerInstance)-[HAS_TASK]->(ECSTask)
    +```
    +
    +
    +
  • +
+
+
+
+

ECSService

+

Representation of an AWS ECS Service

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ARN of the service

region

The region of the service.

name

The name of your service.

arn

The ARN of the service

cluster_arn

The Amazon Resource Name (ARN) of the cluster that hosts the service.

status

The status of the service.

desired_count

The desired number of instantiations of the task definition to keep running on the service.

running_count

The number of tasks in the cluster that are in the RUNNING state.

pending_count

The number of tasks in the cluster that are in the PENDING state.

launch_type

The launch type the service is using.

platform_version

The platform version to run your service on. A platform version is only specified for tasks that are hosted on AWS Fargate.

platform_family

The operating system that your tasks in the service run on. A platform family is specified only for tasks using the Fargate launch type.

task_definition

The task definition to use for tasks in the service.

deployment_config_circuit_breaker_enable

Determines whether to enable the deployment circuit breaker logic for the service.

deployment_config_circuit_breaker_rollback

Determines whether to enable Amazon ECS to roll back the service if a service deployment fails.

deployment_config_maximum_percent

If a service is using the rolling update (ECS) deployment type, the maximum percent parameter represents an upper limit on the number of tasks in a service that are allowed in the RUNNING or PENDING state during a deployment, as a percentage of the desired number of tasks (rounded down to the nearest integer), and while any container instances are in the DRAINING state if the service contains tasks using the EC2 launch type.

deployment_config_minimum_healthy_percent

If a service is using the rolling update (ECS) deployment type, the minimum healthy percent represents a lower limit on the number of tasks in a service that must remain in the RUNNING state during a deployment, as a percentage of the desired number of tasks (rounded up to the nearest integer), and while any container instances are in the DRAINING state if the service contains tasks using the EC2 launch type.

role_arn

The ARN of the IAM role that’s associated with the service.

created_at

The Unix timestamp for the time when the service was created.

health_check_grace_period_seconds

The period of time, in seconds, that the Amazon ECS service scheduler ignores unhealthy Elastic Load Balancing target health checks after a task has first started.

created_by

The principal that created the service.

enable_ecs_managed_tags

Determines whether to enable Amazon ECS managed tags for the tasks in the service.

propagate_tags

Determines whether to propagate the tags from the task definition or the service to the task.

enable_execute_command

Determines whether the execute command functionality is enabled for the service.

+
+

Relationships

+
    +
  • An ECSCluster has ECSService

    +
    ```
    +(ECSCluster)-[HAS_SERVICE]->(ECSService)
    +```
    +
    +
    +
  • +
  • An ECSCluster has ECSContainerInstances

    +
    ```
    +(ECSCluster)-[HAS_CONTAINER_INSTANCE]->(ECSContainerInstance)
    +```
    +
    +
    +
  • +
+
+
+
+

ECSTaskDefinition

+

Representation of an AWS ECS Task Definition

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ARN of the task definition

region

The region of the task definition.

family

The name of a family that this task definition is registered to.

task_role_arn

The short name or full Amazon Resource Name (ARN) of the AWS Identity and Access Management role that grants containers in the task permission to call AWS APIs on your behalf.

execution_role_arn

The Amazon Resource Name (ARN) of the task execution role that grants the Amazon ECS container agent permission to make AWS API calls on your behalf.

network_mode

The Docker networking mode to use for the containers in the task. The valid values are none, bridge, awsvpc, and host. If no network mode is specified, the default is bridge.

revision

The revision of the task in a particular family.

status

The status of the task definition.

compatibilities

The task launch types the task definition validated against during task definition registration.

runtime_platform_cpu_architecture

The CPU architecture.

runtime_platform_operating_system_family

The operating system.

requires_compatibilities

The task launch types the task definition was validated against.

cpu

The number of cpu units used by the task.

memory

The amount (in MiB) of memory used by the task.

pid_mode

The process namespace to use for the containers in the task.

ipc_mode

The IPC resource namespace to use for the containers in the task.

proxy_configuration_type

The proxy type.

proxy_configuration_container_name

The name of the container that will serve as the App Mesh proxy.

registered_at

The Unix timestamp for the time when the task definition was registered.

deregistered_at

The Unix timestamp for the time when the task definition was deregistered.

registered_by

The principal that registered the task definition.

ephemeral_storage_size_in_gib

The total amount, in GiB, of ephemeral storage to set for the task.

+
+

Relationships

+
    +
  • ECSTaskDefinition are a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(ECSTaskDefinition)
    +```
    +
    +
    +
  • +
  • An ECSTask has an ECSTaskDefinition.

    +
    ```
    +(ECSTask)-[HAS_TASK_DEFINITION]->(ECSTaskDefinition)
    +```
    +
    +
    +
  • +
+
+
+
+

ECSContainerDefinition

+

Representation of an AWS ECS Container Definition

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ARN of the task definition, plus the container definition name

region

The region of the container definition.

name

The name of a container.

image

The image used to start a container. This string is passed directly to the Docker daemon.

cpu

The number of cpu units reserved for the container.

memory

The amount (in MiB) of memory to present to the container.

memory_reservation

The soft limit (in MiB) of memory to reserve for the container.

links

The links parameter allows containers to communicate with each other without the need for port mappings.

essential

If the essential parameter of a container is marked as true, and that container fails or stops for any reason, all other containers that are part of the task are stopped.

entry_point

The entry point that’s passed to the container.

command

The command that’s passed to the container.

start_timeout

Time duration (in seconds) to wait before giving up on resolving dependencies for a container.

stop_timeout

Time duration (in seconds) to wait before the container is forcefully killed if it doesn’t exit normally on its own.

hostname

The hostname to use for your container.

user

The user to use inside the container.

working_directory

The working directory to run commands inside the container in.

disable_networking

When this parameter is true, networking is disabled within the container.

privileged

When this parameter is true, the container is given elevated privileges on the host container instance (similar to the root user).

readonly_root_filesystem

When this parameter is true, the container is given read-only access to its root file system.

dns_servers

A list of DNS servers that are presented to the container.

dns_search_domains

A list of DNS search domains that are presented to the container.

docker_security_options

A list of strings to provide custom labels for SELinux and AppArmor multi-level security systems. This field isn’t valid for containers in tasks using the Fargate launch type.

interactive

When this parameter is true, you can deploy containerized applications that require stdin or a tty to be allocated.

pseudo_terminal

When this parameter is true, a TTY is allocated.

+
+

Relationships

+
    +
  • ECSTaskDefinitions have ECSContainerDefinitions

    +
    ```
    +(ECSTaskDefinition)-[HAS_CONTAINER_DEFINITION]->(ECSContainerDefinition)
    +```
    +
    +
    +
  • +
+
+
+
+

ECSTask

+

Representation of an AWS ECS Task

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ARN of the task

region

The region of the task.

arn

The arn of the task.

availability_zone

The Availability Zone for the task.

capacity_provider_name

The capacity provider that’s associated with the task.

cluster_arn

The ARN of the cluster that hosts the task.

connectivity

The connectivity status of a task.

connectivity_at

The Unix timestamp for the time when the task last went into CONNECTED status.

container_instance_arn

The ARN of the container instances that host the task.

cpu

The number of CPU units used by the task as expressed in a task definition.

created_at

The Unix timestamp for the time when the task was created. More specifically, it’s for the time when the task entered the PENDING state.

desired_status

The desired status of the task.

enable_execute_command

Determines whether execute command functionality is enabled for this task.

execution_stopped_at

The Unix timestamp for the time when the task execution stopped.

group

The name of the task group that’s associated with the task.

health_status

The health status for the task.

last_status

The last known status for the task.

launch_type

The infrastructure where your task runs on.

memory

The amount of memory (in MiB) that the task uses as expressed in a task definition.

platform_version

The platform version where your task runs on.

platform_family

The operating system that your tasks are running on.

pull_started_at

The Unix timestamp for the time when the container image pull began.

pull_stopped_at

The Unix timestamp for the time when the container image pull completed.

started_at

The Unix timestamp for the time when the task started. More specifically, it’s for the time when the task transitioned from the PENDING state to the RUNNING state.

started_by

The tag specified when a task is started. If an Amazon ECS service started the task, the startedBy parameter contains the deployment ID of that service.

stop_code

The stop code indicating why a task was stopped.

stopped_at

The Unix timestamp for the time when the task was stopped. More specifically, it’s for the time when the task transitioned from the RUNNING state to the STOPPED state.

stopped_reason

The reason that the task was stopped.

stopping_at

The Unix timestamp for the time when the task stops. More specifically, it’s for the time when the task transitions from the RUNNING state to STOPPED.

task_definition_arn

The ARN of the task definition that creates the task.

version

The version counter for the task.

ephemeral_storage_size_in_gib

The total amount, in GiB, of ephemeral storage to set for the task.

+
+

Relationships

+
    +
  • ECSClusters have ECSTasks

    +
    ```
    +(ECSCluster)-[HAS_TASK]->(ECSTask)
    +```
    +
    +
    +
  • +
  • ECSContainerInstances have ECSTasks

    +
    ```
    +(ECSContainerInstance)-[HAS_TASK]->(ECSTask)
    +```
    +
    +
    +
  • +
  • ECSTasks have ECSTaskDefinitions

    +
    ```
    +(ECSTask)-[HAS_TASK_DEFINITION]->(ECSTaskDefinition)
    +```
    +
    +
    +
  • +
+
+
+
+

ECSContainer

+

Representation of an AWS ECS Container

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ARN of the container

region

The region of the container.

arn

The arn of the container.

task_arn

The ARN of the task.

name

The name of the container.

image

The image used for the container.

image_digest

The container image manifest digest.

runtime_id

The ID of the Docker container.

last_status

The last known status of the container.

exit_code

The exit code returned from the container.

reason

A short (255 max characters) human-readable string to provide additional details about a running or stopped container.

health_status

The health status of the container.

cpu

The number of CPU units set for the container.

memory

The hard limit (in MiB) of memory set for the container.

memory_reservation

The soft limit (in MiB) of memory set for the container.

gpu_ids

The IDs of each GPU assigned to the container.

+
+

Relationships

+
    +
  • ECSTasks have ECSContainers

    +
    ```
    +(ECSTask)-[HAS_CONTAINER]->(ECSContainer)
    +```
    +
    +
    +
  • +
+
+
+
+

SSMInstanceInformation

+

Representation of an AWS SSM InstanceInformation

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ARN of the instance information

region

The region of the instance information.

instance_id

The managed node ID.

ping_status

Connection status of SSM Agent.

last_ping_date_time

The date and time when the agent last pinged the Systems Manager service.

agent_version

The version of SSM Agent running on your Linux managed node.

is_latest_version

Indicates whether the latest version of SSM Agent is running on your Linux managed node. This field doesn’t indicate whether or not the latest version is installed on Windows managed nodes, because some older versions of Windows Server use the EC2Config service to process Systems Manager requests.

platform_type

The operating system platform type.

platform_name

The name of the operating system platform running on your managed node.

platform_version

The version of the OS platform running on your managed node.

activation_id

The activation ID created by AWS Systems Manager when the server or virtual machine (VM) was registered.

iam_role

The AWS Identity and Access Management (IAM) role assigned to the on-premises Systems Manager managed node. This call doesn’t return the IAM role for Amazon Elastic Compute Cloud (Amazon EC2) instances.

registration_date

The date the server or VM was registered with AWS as a managed node.

resource_type

The type of instance. Instances are either EC2 instances or managed instances.

name

The name assigned to an on-premises server, edge device, or virtual machine (VM) when it is activated as a Systems Manager managed node. The name is specified as the DefaultInstanceName property using the CreateActivation command.

ip_address

The IP address of the managed node.

computer_name

The fully qualified host name of the managed node.

association_status

The status of the association.

last_association_execution_date

The date the association was last run.

last_successful_association_execution_date

The last date the association was successfully run.

source_id

The ID of the source resource. For AWS IoT Greengrass devices, SourceId is the Thing name.

source_type

The type of the source resource. For AWS IoT Greengrass devices, SourceType is AWS::IoT::Thing.

+
+

Relationships

+
    +
  • SSMInstanceInformation is a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(SSMInstanceInformation)
    +```
    +
    +
    +
  • +
  • SSMInstanceInformation is a resource of an EC2Instance

    +
    ```
    +(EC2Instance)-[HAS_INFORMATION]->(SSMInstanceInformation)
    +```
    +
    +
    +
  • +
+
+
+
+

SSMInstancePatch

+

Representation of an AWS SSM PatchComplianceData

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ARN of the instance patch

region

The region of the instance patch.

instance_id

The managed node ID.

title

The title of the patch.

kb_id

The operating system-specific ID of the patch.

classification

The classification of the patch, such as SecurityUpdates, Updates, and CriticalUpdates.

severity

The severity of the patch such as Critical, Important, and Moderate.

state

The state of the patch on the managed node, such as INSTALLED or FAILED.

installed_time

The date/time the patch was installed on the managed node. Not all operating systems provide this level of information.

cve_ids

The IDs of one or more Common Vulnerabilities and Exposure (CVE) issues that are resolved by the patch.

+
+

Relationships

+
    +
  • SSMInstancePatch is a resource under the AWS Account.

    +
    ```
    +(AWSAccount)-[RESOURCE]->(SSMInstancePatch)
    +```
    +
    +
    +
  • +
  • EC2Instances have SSMInstancePatches

    +
    ```
    +(EC2Instance)-[HAS_INFORMATION]->(SSMInstancePatch)
    +```
    +
    +
    +
  • +
+
+
+
+
+

Azure Schema

+
+

AzureTenant

+

Representation of an Azure Tenant.

+ ++++ + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The Azure Tenant ID number

+
+

Relationships

+
    +
  • Azure Principal is part of the Azure Account.

    +
    ```
    +(AzureTenant)-[RESOURCE]->(AzurePrincipal)
    +```
    +
    +
    +
  • +
+
+
+
+

AzurePrincipal

+

Representation of an Azure Principal..

+ ++++ + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

email

Email of the Azure Principal

+
+

Relationships

+
    +
  • Azure Principal is part of the Azure Account.

    +
    ```
    +(AzurePrincipal)-[RESOURCE]->(AzureTenant)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureSubscription

+

Representation of an Azure Subscription..

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The Azure Subscription ID number

name

The friendly name that identifies the subscription

path

The full ID for the Subscription

state

Can be one of Enabled | Disabled | Deleted | PastDue | Warned

+
+

Relationships

+
    +
  • Azure Tenant contains one or more Subscriptions.

    +
    ```
    +(AzureTenant)-[RESOURCE]->(AzureSubscription)
    +```
    +
    +
    +
  • +
+
+
+
+

VirtualMachine

+

Representation of an Azure Virtual Machine.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The Azure Virtual Machine ID number

type

The type of the resource

location

The location where Virtual Machine is created

resourcegroup

The Resource Group where Virtual Machine is created

name

The friendly name that identifies the Virtual Machine

plan

The plan associated with the Virtual Machine

size

The size of the Virtual Machine

license_type

The type of license

computer_name

The computer name

identity_type

The type of identity used for the virtual machine

zones

The Virtual Machine zones

ultra_ssd_enabled

Enables or disables a capability on the virtual machine or virtual machine scale set.

priority

Specifies the priority for the virtual machine

eviction_policy

Specifies the eviction policy for the Virtual Machine

+
+

Relationships

+
    +
  • Azure Subscription contains one or more Virtual Machines.

    +
    ```
    +(AzureSubscription)-[RESOURCE]->(VirtualMachine)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureDataDisk

+

Representation of an Azure Data Disk.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The Azure Data Disk ID number

lun

Specifies the logical unit number of the data disk

name

The data disk name

vhd

The virtual hard disk associated with data disk

image

The source user image virtual hard disk

size

The size of the disk in GB

caching

Specifies the caching requirement

createoption

Specifies how the disk should be created

write_accelerator_enabled

Specifies whether writeAccelerator should be enabled or disabled on the data disk

managed_disk_storage_type

The data disk storage type

+
+

Relationships

+
    +
  • Azure Virtual Machines are attached to Data Disks.

    +
    ```
    +(VirtualMachine)-[ATTACHED_TO]->(AzureDataDisk)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureDisk

+

Representation of an Azure Disk.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The Azure Disk ID number

type

The type of the resource

location

The location where Disk is created

resourcegroup

The Resource Group where Disk is created

name

The friendly name that identifies the Disk

createoption

Specifies how the disk should be created

disksizegb

The size of the disk in GB

encryption

Specifies whether the disk has encryption enabled

maxshares

Specifies how many machines can share the disk

ostype

The operating system type of the disk

tier

Performance Tier associated with the disk

sku

The disk sku name

zones

The logical zone list for disk

+
+

Relationships

+
    +
  • Azure Subscription contains one or more Disks.

    +
    ```
    +(AzureSubscription)-[RESOURCE]->(AzureDisk)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureSnapshot

+

Representation of an Azure Snapshot.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The Azure Snapshot ID number

type

The type of the resource

location

The location where snapshot is created

resourcegroup

The Resource Group where snapshot is created

name

The friendly name that identifies the snapshot

createoption

Specifies how the disk should be created

disksizegb

The size of the snapshot in GB

encryption

Specifies whether the snapshot has encryption enabled

incremental

Indicates whether a snapshot is incremental or not

network_access_policy

Policy for accessing the snapshot via network

ostype

The operating system type of the snapshot

tier

Performance Tier associated with the snapshot

sku

The snapshot sku name

zones

The logical zone list for snapshot

+
+

Relationships

+
    +
  • Azure Subscription contains one or more Snapshots.

    +
    ```
    +(AzureSubscription)-[RESOURCE]->(AzureSnapshot)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureSQLServer

+

Representation of an AzureSQLServer.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The resource ID

location

The location where the resource is created

resourcegroup

The Resource Group where SQL Server is created

name

The friendly name that identifies the SQL server

kind

Specifies the kind of SQL server

state

The state of the server

version

The version of the server

+
+

Relationships

+
    +
  • Azure Subscription contains one or more SQL Servers.

    +
    ```
    +(AzureSubscription)-[RESOURCE]->(AzureSQLServer)
    +```
    +
    +
    +
  • +
  • Azure SQL Server can be used by one or more Azure Server DNS Aliases.

    +
    ```
    +(AzureSQLServer)-[USED_BY]->(AzureServerDNSAlias)
    +```
    +
    +
    +
  • +
  • Azure SQL Server can be administered by one or more Azure Server AD Administrators.

    +
    ```
    +(AzureSQLServer)-[ADMINISTERED_BY]->(AzureServerADAdministrator)
    +```
    +
    +
    +
  • +
  • Azure SQL Server has one or more Azure Recoverable Database.

    +
    ```
    +(AzureSQLServer)-[RESOURCE]->(AzureRecoverableDatabase)
    +```
    +
    +
    +
  • +
  • Azure SQL Server has one or more Azure Restorable Dropped Database.

    +
    ```
    +(AzureSQLServer)-[RESOURCE]->(AzureRestorableDroppedDatabase)
    +```
    +
    +
    +
  • +
  • Azure SQL Server has one or more Azure Failover Group.

    +
    ```
    +(AzureSQLServer)-[RESOURCE]->(AzureFailoverGroup)
    +```
    +
    +
    +
  • +
  • Azure SQL Server has one or more Azure Elastic Pool.

    +
    ```
    +(AzureSQLServer)-[RESOURCE]->(AzureElasticPool)
    +```
    +
    +
    +
  • +
  • Azure SQL Server has one or more Azure SQL Database.

    +
    ```
    +(AzureSQLServer)-[RESOURCE]->(AzureSQLDatabase)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureServerDNSAlias

+

Representation of an AzureServerDNSAlias.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The resource ID

name

The name of the server DNS alias

dnsrecord

The fully qualified DNS record for alias.

+
+

Relationships

+
    +
  • Azure SQL Server can be used by one or more Azure Server DNS Aliases.

    +
    ```
    +(AzureSQLServer)-[USED_BY]->(AzureServerDNSAlias)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureServerADAdministrator

+

Representation of an AzureServerADAdministrator.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The resource ID

name

The name of the resource.

administratortype

The type of the server administrator.

login

The login name of the server administrator.

+
+

Relationships

+
    +
  • Azure SQL Server can be administered by one or more Azure Server AD Administrators.

    +
    ```
    +(AzureSQLServer)-[ADMINISTERED_BY]->(AzureServerADAdministrator)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureRecoverableDatabase

+

Representation of an AzureRecoverableDatabase.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The resource ID

name

The name of the resource.

edition

The edition of the database.

servicelevelobjective

The service level objective name of the database.

lastbackupdate

The last available backup date of the database (ISO8601 format).

+
+

Relationships

+
    +
  • Azure SQL Server has one or more Azure Recoverable Database.

    +
    ```
    +(AzureSQLServer)-[RESOURCE]->(AzureRecoverableDatabase)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureRestorableDroppedDatabase

+

Representation of an AzureRestorableDroppedDatabase.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The resource ID

name

The name of the resource.

location

The geo-location where the resource lives.

databasename

The name of the database.

creationdate

The creation date of the database (ISO8601 format).

deletiondate

The deletion date of the database (ISO8601 format).

restoredate

The earliest restore date of the database (ISO8601 format).

edition

The edition of the database.

servicelevelobjective

The service level objective name of the database.

maxsizebytes

The max size in bytes of the database.

+
+

Relationships

+
    +
  • Azure SQL Server has one or more Azure Restorable Dropped Database.

    +
    ```
    +(AzureSQLServer)-[RESOURCE]->(AzureRestorableDroppedDatabase)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureFailoverGroup

+

Representation of an AzureFailoverGroup.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The resource ID

name

The name of the resource.

location

The geo-location where the resource lives.

replicationrole

Local replication role of the failover group instance.

replicationstate

Replication state of the failover group instance.

+
+

Relationships

+
    +
  • Azure SQL Server has one or more Azure Failover Group.

    +
    ```
    +(AzureSQLServer)-[RESOURCE]->(AzureFailoverGroup)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureElasticPool

+

Representation of an AzureElasticPool.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The resource ID

name

The name of the resource.

location

The location of the resource.

kind

The kind of elastic pool.

creationdate

The creation date of the elastic pool (ISO8601 format).

state

The state of the elastic pool.

maxsizebytes

The storage limit for the database elastic pool in bytes.

licensetype

The license type to apply for this elastic pool.

zoneredundant

Specifies whether or not this elastic pool is zone redundant, which means the replicas of this elastic pool will be spread across multiple availability zones.

+
+

Relationships

+
    +
  • Azure SQL Server has one or more Azure Elastic Pool.

    +
    ```
    +(AzureSQLServer)-[RESOURCE]->(AzureElasticPool)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureSQLDatabase

+

Representation of an AzureSQLDatabase.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The resource ID

name

The name of the resource.

location

The location of the resource.

kind

The kind of database.

creationdate

The creation date of the database (ISO8601 format).

databaseid

The ID of the database.

maxsizebytes

The max size of the database expressed in bytes.

licensetype

The license type to apply for this database.

secondarylocation

The default secondary region for this database.

elasticpoolid

The resource identifier of the elastic pool containing this database.

collation

The collation of the database.

failovergroupid

Failover Group resource identifier that this database belongs to.

zoneredundant

Whether or not this database is zone redundant, which means the replicas of this database will be spread across multiple availability zones.

restorabledroppeddbid

The resource identifier of the restorable dropped database associated with create operation of this database.

recoverabledbid

The resource identifier of the recoverable database associated with create operation of this database.

+
+

Relationships

+
    +
  • Azure SQL Server has one or more Azure SQL Database.

    +
    ```
    +(AzureSQLServer)-[RESOURCE]->(AzureSQLDatabase)
    +```
    +
    +
    +
  • +
  • Azure SQL Database contains one or more Azure Replication Links.

    +
    ```
    +(AzureSQLDatabase)-[CONTAINS]->(AzureReplicationLink)
    +```
    +
    +
    +
  • +
  • Azure SQL Database contains a Database Threat Detection Policy.

    +
    ```
    +(AzureSQLDatabase)-[CONTAINS]->(AzureDatabaseThreatDetectionPolicy)
    +```
    +
    +
    +
  • +
  • Azure SQL Database contains one or more Restore Points.

    +
    ```
    +(AzureSQLDatabase)-[CONTAINS]->(AzureRestorePoint)
    +```
    +
    +
    +
  • +
  • Azure SQL Database contains Transparent Data Encryption.

    +
    ```
    +(AzureSQLDatabase)-[CONTAINS]->(AzureTransparentDataEncryption)
    +```
    +
    +
    +
  • +
+
+
+ +
+

AzureDatabaseThreatDetectionPolicy

+

Representation of an AzureDatabaseThreatDetectionPolicy.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The resource ID

name

The name of the resource.

location

The geo-location where the resource lives.

kind

The kind of the resource.

emailadmins

Specifies that the alert is sent to the account administrators.

emailaddresses

Specifies the semicolon-separated list of e-mail addresses to which the alert is sent.

retentiondays

Specifies the number of days to keep in the Threat Detection audit logs.

state

Specifies the state of the policy.

storageendpoint

Specifies the blob storage endpoint.

useserverdefault

Specifies whether to use the default server policy.

disabledalerts

Specifies the semicolon-separated list of alerts that are disabled, or empty string to disable no alerts.

+
+

Relationships

+
    +
  • Azure SQL Database contains a Database Threat Detection Policy.

    +
    ```
    +(AzureSQLDatabase)-[CONTAINS]->(AzureDatabaseThreatDetectionPolicy)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureRestorePoint

+

Representation of an AzureRestorePoint.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The resource ID

name

The name of the resource.

location

The geo-location where the resource lives.

restoredate

The earliest time to which this database can be restored.

restorepointtype

The type of restore point.

creationdate

The time the backup was taken.

+
+

Relationships

+
    +
  • Azure SQL Database contains one or more Restore Points.

    +
    ```
    +(AzureSQLDatabase)-[CONTAINS]->(AzureRestorePoint)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureTransparentDataEncryption

+

Representation of an AzureTransparentDataEncryption.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The resource ID

name

The name of the resource.

location

The resource location.

status

The status of the database transparent data encryption.

+
+

Relationships

+
    +
  • Azure SQL Database contains Transparent Data Encryption.

    +
    ```
    +(AzureSQLDatabase)-[CONTAINS]->(AzureTransparentDataEncryption)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureStorageAccount

+

Representation of an AzureStorageAccount.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Fully qualified resource ID for the resource.

type

The type of the resource.

location

The geo-location where the resource lives.

resourcegroup

The Resource Group where the storage account is created

name

The name of the resource.

kind

Gets the Kind of the resource.

creationtime

Gets the creation date and time of the storage account in UTC.

hnsenabled

Specifies if the Account HierarchicalNamespace is enabled.

primarylocation

Gets the location of the primary data center for the storage account.

secondarylocation

Gets the location of the geo-replicated secondary for the storage account.

provisioningstate

Gets the status of the storage account at the time the operation was called.

statusofprimary

Gets the status availability status of the primary location of the storage account.

statusofsecondary

Gets the status availability status of the secondary location of the storage account.

supportshttpstrafficonly

Allows https traffic only to storage service if sets to true.

+
+

Relationships

+
    +
  • Azure Subscription contains one or more Storage Accounts.

    +
    ```
    +(AzureSubscription)-[RESOURCE]->(AzureStorageAccount)
    +```
    +
    +
    +
  • +
  • Azure Storage Accounts uses one or more Queue Services.

    +
    ```
    +(AzureStorageAccount)-[USES]->(AzureStorageQueueService)
    +```
    +
    +
    +
  • +
  • Azure Storage Accounts uses one or more Table Services.

    +
    ```
    +(AzureStorageAccount)-[USES]->(AzureStorageTableService)
    +```
    +
    +
    +
  • +
  • Azure Storage Accounts uses one or more File Services.

    +
    ```
    +(AzureStorageAccount)-[USES]->(AzureStorageFileService)
    +```
    +
    +
    +
  • +
  • Azure Storage Accounts uses one or more Blob Services.

    +
    ```
    +(AzureStorageAccount)-[USES]->(AzureStorageBlobService)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureStorageQueueService

+

Representation of an AzureStorageQueueService.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Fully qualified resource ID for the resource.

type

The type of the resource.

name

The name of the queue service.

+
+

Relationships

+
    +
  • Azure Storage Accounts uses one or more Queue Services.

    +
    ```
    +(AzureStorageAccount)-[USES]->(AzureStorageQueueService)
    +```
    +
    +
    +
  • +
  • Queue Service contains one or more queues.

    +
    ```
    +(AzureStorageQueueService)-[CONTAINS]->(AzureStorageQueue)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureStorageTableService

+

Representation of an AzureStorageTableService.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Fully qualified resource ID for the resource.

type

The type of the resource.

name

The name of the table service.

+
+

Relationships

+
    +
  • Azure Storage Accounts uses one or more Table Services.

    +
    ```
    +(AzureStorageAccount)-[USES]->(AzureStorageTableService)
    +```
    +
    +
    +
  • +
  • Table Service contains one or more tables.

    +
    ```
    +(AzureStorageTableService)-[CONTAINS]->(AzureStorageTable)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureStorageFileService

+

Representation of an AzureStorageFileService.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Fully qualified resource ID for the resource.

type

The type of the resource.

name

The name of the file service.

+
+

Relationships

+
    +
  • Azure Storage Accounts uses one or more File Services.

    +
    ```
    +(AzureStorageAccount)-[USES]->(AzureStorageFileService)
    +```
    +
    +
    +
  • +
  • Table Service contains one or more file shares.

    +
    ```
    +(AzureStorageFileService)-[CONTAINS]->(AzureStorageFileShare)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureStorageBlobService

+

Representation of an AzureStorageBlobService.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Fully qualified resource ID for the resource.

type

The type of the resource.

name

The name of the blob service.

+
+

Relationships

+
    +
  • Azure Storage Accounts uses one or more Blob Services.

    +
    ```
    +(AzureStorageAccount)-[USES]->(AzureStorageBlobService)
    +```
    +
    +
    +
  • +
  • Blob Service contains one or more blob containers.

    +
    ```
    +(AzureStorageBlobService)-[CONTAINS]->(AzureStorageBlobContainer)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureStorageQueue

+

Representation of an AzureStorageQueue.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Fully qualified resource ID for the resource.

type

The type of the resource.

name

The name of the queue.

+
+

Relationships

+
    +
  • Queue Service contains one or more queues.

    +
    ```
    +(AzureStorageQueueService)-[CONTAINS]->(AzureStorageQueue)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureStorageTable

+

Representation of an AzureStorageTable.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Fully qualified resource ID for the resource.

type

The type of the resource.

name

The name of the table resource.

tablename

Table name under the specified account.

+
+

Relationships

+
    +
  • Table Service contains one or more tables.

    +
    ```
    +(AzureStorageTableService)-[CONTAINS]->(AzureStorageTable)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureStorageFileShare

+

Representation of an AzureStorageFileShare.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Fully qualified resource ID for the resource.

type

The type of the resource.

name

The name of the resource.

lastmodifiedtime

Specifies the date and time the share was last modified.

sharequota

The maximum size of the share, in gigabytes.

accesstier

Specifies the access tier for the share.

deleted

Indicates whether the share was deleted.

accesstierchangetime

Indicates the last modification time for share access tier.

accesstierstatus

Indicates if there is a pending transition for access tier.

deletedtime

The deleted time if the share was deleted.

enabledprotocols

The authentication protocol that is used for the file share.

remainingretentiondays

Remaining retention days for share that was soft deleted.

shareusagebytes

The approximate size of the data stored on the share.

version

The version of the share.

+
+

Relationships

+
    +
  • File Service contains one or more file shares.

    +
    ```
    +(AzureStorageTableService)-[CONTAINS]->(AzureStorageFileShare)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureStorageBlobContainer

+

Representation of an AzureStorageBlobContainer.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Fully qualified resource ID for the resource.

type

The type of the resource.

name

The name of the resource.

deleted

Indicates whether the blob container was deleted.

deletedtime

Blob container deletion time.

defaultencryptionscope

Default the container to use specified encryption scope for all writes.

publicaccess

Specifies whether data in the container may be accessed publicly and the level of access.

leasestatus

The lease status of the container.

leasestate

Lease state of the container.

lastmodifiedtime

Specifies the date and time the container was last modified.

remainingretentiondays

Specifies the remaining retention days for soft deleted blob container.

version

The version of the deleted blob container.

hasimmutabilitypolicy

Specifies the if the container has an ImmutabilityPolicy or not.

haslegalhold

Specifies if the container has any legal hold tags.

leaseduration

Specifies whether the lease on a container is of infinite or fixed duration, only when the container is leased.

+
+

Relationships

+
    +
  • Blob Service contains one or more blob containers.

    +
    ```
    +(AzureStorageBlobService)-[CONTAINS]->(AzureStorageBlobContainer)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureCosmosDBAccount

+

Representation of an AzureCosmosDBAccount.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The unique resource identifier of the ARM resource.

location

The location of the resource group to which the resource belongs.

resourcegroup

The Resource Group where the database account is created.

name

The name of the ARM resource.

kind

Indicates the type of database account.

type

The type of Azure resource.

ipranges

List of IpRules.

capabilities

List of Cosmos DB capabilities for the account.

documentendpoint

The connection endpoint for the Cosmos DB database account.

virtualnetworkfilterenabled

Flag to indicate whether to enable/disable Virtual Network ACL rules.

enableautomaticfailover

Enables automatic failover of the write region in the rare event that the region is unavailable due to an outage.

provisioningstate

The status of the Cosmos DB account at the time the operation was called.

multiplewritelocations

Enables the account to write in multiple locations.

accountoffertype

The offer type for the Cosmos DB database account.

publicnetworkaccess

Whether requests from Public Network are allowed.

enablecassandraconnector

Enables the cassandra connector on the Cosmos DB C* account.

connectoroffer

The cassandra connector offer type for the Cosmos DB database C* account.

disablekeybasedmetadatawriteaccess

Disable write operations on metadata resources (databases, containers, throughput) via account keys.

keyvaulturi

The URI of the key vault.

enablefreetier

Flag to indicate whether Free Tier is enabled.

enableanalyticalstorage

Flag to indicate whether to enable storage analytics.

defaultconsistencylevel

The default consistency level and configuration settings of the Cosmos DB account.

maxstalenessprefix

When used with the Bounded Staleness consistency level, this value represents the number of stale requests tolerated.

maxintervalinseconds

When used with the Bounded Staleness consistency level, this value represents the time amount of staleness (in seconds) tolerated.

+
+

Relationships

+
    +
  • Azure Subscription contains one or more database accounts.

    +
    ```
    +(AzureSubscription)-[RESOURCE]->(AzureCosmosDBAccount)
    +```
    +
    +
    +
  • +
  • Azure Database Account can be read from, written from and is associated with Azure CosmosDB Locations.

    +
    ```
    +(AzureCosmosDBAccount)-[CAN_WRITE_FROM]->(AzureCosmosDBLocation)
    +```
    +(AzureCosmosDBAccount)-[CAN_READ_FROM]->(AzureCosmosDBLocation)
    +```
    +(AzureCosmosDBAccount)-[ASSOCIATED_WITH]->(AzureCosmosDBLocation)
    +```
    +
    +
    +
  • +
  • Azure Database Account contains one or more Cors Policy.

    +
    ```
    +(AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBCorsPolicy)
    +```
    +
    +
    +
  • +
  • Azure Database Account contains one or more failover policies.

    +
    ```
    +(AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBAccountFailoverPolicy)
    +```
    +
    +
    +
  • +
  • Azure Database Account is configured with one or more private endpoint connections.

    +
    ```
    +(AzureCosmosDBAccount)-[CONFIGURED_WITH]->(AzureCDBPrivateEndpointConnection)
    +```
    +
    +
    +
  • +
  • Azure Database Account is configured with one or more virtual network rules.

    +
    ```
    +(AzureCosmosDBAccount)-[CONFIGURED_WITH]->(AzureCosmosDBVirtualNetworkRule)
    +```
    +
    +
    +
  • +
  • Azure Database Account contains one or more SQL databases.

    +
    ```
    +(AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBSqlDatabase)
    +```
    +
    +
    +
  • +
  • Azure Database Account contains one or more Cassandra keyspace.

    +
    ```
    +(AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBCassandraKeyspace)
    +```
    +
    +
    +
  • +
  • Azure Database Account contains one or more MongoDB Database.

    +
    ```
    +(AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBMongoDBDatabase)
    +```
    +
    +
    +
  • +
  • Azure Database Account contains one or more table resource.

    +
    ```
    +(AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBTableResource)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureCosmosDBLocation

+

Representation of an Azure CosmosDB Location.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The unique identifier of the region within the database account.

locationname

The name of the region.

documentendpoint

The connection endpoint for the specific region.

provisioningstate

The status of the Cosmos DB account at the time the operation was called.

failoverpriority

The failover priority of the region.

iszoneredundant

Flag to indicate whether or not this region is an AvailabilityZone region.

+
+

Relationships

+
    +
  • Azure Database Account has write permissions from, read permissions from and is associated with Azure CosmosDB Locations.

    +
    ```
    +(AzureCosmosDBAccount)-[CAN_WRITE_FROM]->(AzureCosmosDBLocation)
    +```
    +(AzureCosmosDBAccount)-[CAN_READ_FROM]->(AzureCosmosDBLocation)
    +```
    +(AzureCosmosDBAccount)-[ASSOCIATED_WITH]->(AzureCosmosDBLocation)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureCosmosDBCorsPolicy

+

Representation of an Azure Cosmos DB Cors Policy.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The unique resource identifier for Cors Policy.

allowedorigins

The origin domains that are permitted to make a request against the service via CORS.

allowedmethods

The methods (HTTP request verbs) that the origin domain may use for a CORS request.

allowedheaders

The request headers that the origin domain may specify on the CORS request.

exposedheaders

The response headers that may be sent in the response to the CORS request and exposed by the browser to the request issuer.

maxageinseconds

The maximum amount time that a browser should cache the preflight OPTIONS request.

+
+

Relationships

+
    +
  • Azure Database Account contains one or more Cors Policy.

    +
    ```
    +(AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBCorsPolicy)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureCosmosDBAccountFailoverPolicy

+

Representation of an Azure Database Account Failover Policy.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The unique identifier of the region in which the database account replicates to.

locationname

The name of the region in which the database account exists.

failoverpriority

The failover priority of the region. A failover priority of 0 indicates a write region.

+
+

Relationships

+
    +
  • Azure Database Account contains one or more failover policies.

    +
    ```
    +(AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBAccountFailoverPolicy)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureCDBPrivateEndpointConnection

+

Representation of an Azure Cosmos DB Private Endpoint Connection.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Fully qualified resource Id for the resource.

name

The name of the resource.

privateendpointid

Resource id of the private endpoint.

status

The private link service connection status.

actionrequired

Any action that is required beyond basic workflow (approve/ reject/ disconnect).

+
+

Relationships

+
    +
  • Azure Database Account is configured with one or more private endpoint connections.

    +
    ```
    +(AzureCosmosDBAccount)-[CONFIGURED_WITH]->(AzureCDBPrivateEndpointConnection)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureCosmosDBVirtualNetworkRule

+

Representation of an Azure Cosmos DB Virtual Network Rule.

+ ++++ + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Resource ID of a subnet.

ignoremissingvnetserviceendpoint

Create firewall rule before the virtual network has vnet service endpoint enabled.

+
+

Relationships

+
    +
  • Azure Database Account is configured with one or more virtual network rules.

    +
    ```
    +(AzureCosmosDBAccount)-[CONFIGURED_WITH]->(AzureCosmosDBVirtualNetworkRule)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureCosmosDBSqlDatabase

+

Representation of an AzureCosmosDBSqlDatabase.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The unique resource identifier of the ARM resource.

name

The name of the ARM resource.

type

The type of Azure resource.

location

The location of the resource group to which the resource belongs.

throughput

Value of the Cosmos DB resource throughput or autoscaleSettings.

maxthroughput

Represents maximum throughput, the resource can scale up to.

+
+

Relationships

+
    +
  • Azure Database Account contains one or more SQL databases.

    +
    ```
    +(AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBSqlDatabase)
    +```
    +
    +
    +
  • +
  • SQL Databases contain one or more SQL containers.

    +
    ```
    +(AzureCosmosDBSqlDatabase)-[CONTAINS]->(AzureCosmosDBSqlContainer)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureCosmosDBCassandraKeyspace

+

Representation of an AzureCosmosDBCassandraKeyspace.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The unique resource identifier of the ARM resource.

name

The name of the ARM resource.

type

The type of Azure resource.

location

The location of the resource group to which the resource belongs.

throughput

Value of the Cosmos DB resource throughput or autoscaleSettings.

maxthroughput

Represents maximum throughput, the resource can scale up to.

+
+

Relationships

+
    +
  • Azure Database Account contains one or more Cassandra keyspace.

    +
    ```
    +(AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBCassandraKeyspace)
    +```
    +
    +
    +
  • +
  • Cassandra Keyspace contains one or more Cassandra tables.

    +
    ```
    +(AzureCosmosDBCassandraKeyspace)-[CONTAINS]->(AzureCosmosDBCassandraTable)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureCosmosDBMongoDBDatabase

+

Representation of an AzureCosmosDBMongoDBDatabase.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The unique resource identifier of the ARM resource.

name

The name of the ARM resource.

type

The type of Azure resource.

location

The location of the resource group to which the resource belongs.

throughput

Value of the Cosmos DB resource throughput or autoscaleSettings.

maxthroughput

Represents maximum throughput, the resource can scale up to.

+
+

Relationships

+
    +
  • Azure Database Account contains one or more MongoDB Database.

    +
    ```
    +(AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBMongoDBDatabase)
    +```
    +
    +
    +
  • +
  • MongoDB database contains one or more MongoDB collections.

    +
    ```
    +(AzureCosmosDBMongoDBDatabase)-[CONTAINS]->(AzureCosmosDBMongoDBCollection)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureCosmosDBTableResource

+

Representation of an AzureCosmosDBTableResource.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The unique resource identifier of the ARM resource.

name

The name of the ARM resource.

type

The type of Azure resource.

location

The location of the resource group to which the resource belongs.

throughput

Value of the Cosmos DB resource throughput or autoscaleSettings.

maxthroughput

Represents maximum throughput, the resource can scale up to.

+
+

Relationships

+
    +
  • Azure Database Account contains one or more table resource.

    +
    ```
    +(AzureCosmosDBAccount)-[CONTAINS]->(AzureCosmosDBTableResource)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureCosmosDBSqlContainer

+

Representation of an AzureCosmosDBSqlContainer.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The unique resource identifier of the ARM resource.

name

The name of the ARM resource.

type

The type of Azure resource.

location

The location of the resource group to which the resource belongs.

throughput

Value of the Cosmos DB resource throughput or autoscaleSettings.

maxthroughput

Represents maximum throughput, the resource can scale up to.

container

Name of the Cosmos DB SQL container.

defaultttl

Default time to live.

analyticalttl

Specifies the Analytical TTL.

isautomaticindexingpolicy

Indicates if the indexing policy is automatic.

indexingmode

Indicates the indexing mode.

conflictresolutionpolicymode

Indicates the conflict resolution mode.

+
+

Relationships

+
    +
  • SQL Databases contain one or more SQL containers.

    +
    ```
    +(AzureCosmosDBSqlDatabase)-[CONTAINS]->(AzureCosmosDBSqlContainer)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureCosmosDBCassandraTable

+

Representation of an AzureCosmosDBCassandraTable.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The unique resource identifier of the ARM resource.

name

The name of the ARM resource.

type

The type of Azure resource.

location

The location of the resource group to which the resource belongs.

throughput

Value of the Cosmos DB resource throughput or autoscaleSettings.

maxthroughput

Represents maximum throughput, the resource can scale up to.

container

Name of the Cosmos DB Cassandra table.

defaultttl

Time to live of the Cosmos DB Cassandra table.

analyticalttl

Specifies the Analytical TTL.

+
+

Relationships

+
    +
  • Cassandra Keyspace contains one or more Cassandra tables.

    +
    ```
    +(AzureCosmosDBCassandraKeyspace)-[CONTAINS]->(AzureCosmosDBCassandraTable)
    +```
    +
    +
    +
  • +
+
+
+
+

AzureCosmosDBMongoDBCollection

+

Representation of an AzureCosmosDBMongoDBCollection.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The unique resource identifier of the ARM resource.

name

The name of the ARM resource.

type

The type of Azure resource.

location

The location of the resource group to which the resource belongs.

throughput

Value of the Cosmos DB resource throughput or autoscaleSettings.

maxthroughput

Represents maximum throughput, the resource can scale up to.

collectionname

Name of the Cosmos DB MongoDB collection.

analyticalttl

Specifies the Analytical TTL.

+
+

Relationships

+
    +
  • MongoDB database contains one or more MongoDB collections.

    +
    ```
    +(AzureCosmosDBMongoDBDatabase)-[CONTAINS]->(AzureCosmosDBMongoDBCollection)
    +```
    +
    +
    +
  • +
+
+
+
+
+

Crxcavtor Schema

+
+

GSuiteUser

+

Placeholder representation of a single G Suite user object. This node is the minimal data necessary to map who has extensions installed until full G Suite data is imported.

+ ++++ + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The user’s email address, will change to actual G Suite id in future

email

The user’s email address

+
+

Relationships

+
    +
  • GSuiteUsers install ChromeExtensions.

    +
    (GSuiteUser)-[INSTALLS]->(ChromeExtension)
    +
    +
    +
  • +
+
+
+
+

ChromeExtension

+
+

Representation of a CRXcavator Chrome Extension Report.

+
+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The combined extension name and version e.g. "Docs|1.0"

extension_id

CRXcavator id for extension.

version

The versions of the extension in this report

risk_total

CRXcavator risk score for the extension

risk_metadata

Additional data provided by CRXcavator on the risk score

risk_permissions_score

Sum of the permissions component of the risk score

risk_webstore_score

Sum of the webstore component of the risk score

risk_csp_score

Sum of the CSP component of the risk score

risk_optional_permissions_score

Sum of the optional permissions component of the risk score

risk_extcalls_score

Sum of the external calls component of the risk score

risk_vuln_score

Sum of the RetireJS vulnerability component of the risk score

address

Physical address of extension developer

email

Email address of extension developer

icon

URL of the extension icon

crxcavator_last_updated

Date the extension was last updated in the webstore

name

Full name of the extension

offered_by

Name of the extension developer

permissions_warnings

Concatenated list of permissions warnings for the extension

privacy_policy

URL of privacy policy for extension

rating

Current webstore rating for extension

rating_users

How many users have provided a rating for the extension

short_description

Summary of what extension does

size

Size of extension download

support_site

URL of developer support site

users

Webstore count of extension users

website

Developer URL for extension

type

Extension categorization

price

Extension price in webstore if applicable

report_link

URL of full extension report on crxcavator.io

+
+

Relationships

+
    +
  • GSuiteUsers install ChromeExtensions.

    +
    (GSuiteUser)-[INSTALLS]->(ChromeExtension)
    +
    +
    +
  • +
+
+
+
+
+

DigitalOcean Schema

+
+

DOAccount

+

Representation of a DigitalOcean Account object.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The UUID of the account

uuid

The UUID of the account (same value as id)

droplet_limit

Total number of droplets that the account can have at one time

floating_ip_limit

Total number of floating IPs the account may have

status

Status of the account

+
+

Relationships

+
    +
  • DOAccount contains DOProjects.

    +
    (DOAccount)-[RESOURCE]->(DOProjects)
    +
    +
    +
  • +
+
+
+
+

DOProject

+

Representation of a DigitalOcean Project object.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The unique universal identifier of the project

account_id

Id of the DOAccount where this project belongs to

description

The description of the project

environment

The environment of the project’s resources

is_default

If true, all resources will be added to this project if no project is specified

name

The human-readable name for the project

owner_uuid

The unique universal identifier of the project’s owner

created_at

A time value given in ISO8601 combined date and time format that represents when the project was created

updated_at

A time value given in ISO8601 combined date and time format that represents when the project was updated

+
+

Relationships

+
    +
  • DOProject has DODroplets as resource.

    +
    (DOProject)-[RESOURCE]->(DODroplet)
    +
    +
    +
  • +
+
+
+
+

DODroplet

+

Representation of a DigitalOcean Droplet object.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

A unique identifier for each Droplet instance

account_id

Id of the DOAccount where this Droplet belongs to

features

An array of features enabled on this Droplet

locked

A boolean value indicating whether the Droplet has been locked, preventing actions by users

image

The slug of the base image used to create the Droplet instance

ip_address

The v4 external ip address of this Droplet

ip_v6_address

The v6 external ip address of this Droplet

kernel

The current kernel image id

name

The human-readable name set for the Droplet instance

private_ip_address

The v4 internal ip address of this Droplet

project_id

Id of the DOProject where this Droplet belongs to

region

The region that the Droplet instance is deployed in

size

The current size object describing the Droplet

status

A status string indicating the state of the Droplet instance.This may be “new”, “active”, “off”, or “archive”

tags

An array of Tags the Droplet has been tagged with

volumes

A flat array including the unique identifier for each Block Storage volume attached to the Droplet

created_at

A time value given in ISO8601 combined date and time format that represents when the Droplet was created

+
+

Relationships

+
    +
  • DODroplet is a resource of a DOProject.

    +
    (DODroplet)<-[RESOURCE]-(DOProject)
    +
    +
    +
  • +
+
+
+
+
+

GCP Schema

+
+

GCPOrganization

+

Representation of a GCP Organization object.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The name of the GCP Organization, e.g. “organizations/1234”

displayname

The “friendly name”, e.g. “My Company”

lifecyclestate

The organization’s current lifecycle state. Assigned by the server. See the official docs.

+
+

Relationships

+
    +
  • GCPOrganizations contain GCPFolders.

    +
    (GCPOrganization)-[RESOURCE]->(GCPFolder)
    +
    +
    +
  • +
  • GCPOrganizations can contain GCPProjects.

    +
    (GCPOrganization)-[RESOURCE]->(GCPProjects)
    +
    +
    +
  • +
+
+
+
+

GCPFolder

+
+

Representation of a GCP Folder. An additional helpful reference is the Google Compute Platform resource hierarchy.

+
+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The name of the folder, e.g. “folders/1234”

displayname

A friendly name of the folder, e.g. “My Folder”.

lifecyclestate

The folder’s current lifecycle state. Assigned by the server. See the official docs.

+
+

Relationships

+
    +
  • GCPOrganizations are parents of GCPFolders.

    +
    (GCPOrganization)<-[PARENT]-(GCPFolder)
    +
    +
    +
  • +
  • GCPFolders can contain GCPProjects

    +
    (GCPFolder)-[RESOURCE]->(GCPProject)
    +
    +
    +
  • +
  • GCPFolders can contain other GCPFolders.

    +
    (GCPFolder)-[RESOURCE]->(GCPFolder)
    +
    +
    +
  • +
+
+
+
+

GCPProject

+
+

Representation of a GCP Project. An additional helpful reference is the Google Compute Platform resource hierarchy.

+
+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the project, e.g. “sys-12345”

projectnumber

The number uniquely identifying the project, e.g. ‘987654’

displayname

A friendly name of the project, e.g. “MyProject”.

lifecyclestate

The project’s current lifecycle state. Assigned by the server. See the official docs.

+
+
+

Relationships

+
    +
  • GCPOrganizations contain GCPProjects.

    +
    (GCPOrganization)-[RESOURCE]->(GCPProjects)
    +
    +
    +
      +
    • GCPFolders can contain GCPProjects

      +
      (GCPFolder)-[RESOURCE]->(GCPProject)
      +
      +
      +
    • +
    +
  • +
  • GCPVpcs are part of GCPProjects

    +
    (GCPProject)-[RESOURCE]->(GCPVpc)
    +
    +
    +
  • +
+
+
+

GCPBucket

+

Representation of a GCP Storage Bucket.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the storage bucket, e.g. “bucket-12345”

projectnumber

The number uniquely identifying the project associated with the storage bucket, e.g. ‘987654’

self_link

The URI of the storage bucket

kind

The kind of item this is. For storage buckets, this is always storage#bucket

location

The location of the bucket. Object data for objects in the bucket resides in physical storage within this region. Defaults to US. See Cloud Storage bucket locations for the authoritative list.

location_type

The type of location that the bucket resides in, as determined by the location property

meta_generation

The metadata generation of this bucket

storage_class

The bucket’s default storage class, used whenever no storageClass is specified for a newly-created object. For more information, see storage classes

time_created

The creation time of the bucket in RFC 3339 format

retention_period

The period of time, in seconds, that objects in the bucket must be retained and cannot be deleted, overwritten, or archived

iam_config_bucket_policy_only

The bucket’s Bucket Policy Only configuration

owner_entity

The entity, in the form project-owner-projectId

owner_entity_id

The ID for the entity

versioning_enabled

The bucket’s versioning configuration (if set to True, versioning is fully enabled for this bucket)

log_bucket

The destination bucket where the current bucket’s logs should be placed

requester_pays

The bucket’s billing configuration (if set to true, Requester Pays is enabled for this bucket)

default_kms_key_name

A Cloud KMS key that will be used to encrypt objects inserted into this bucket, if no encryption method is specified

+
+

Relationships

+
    +
  • GCPBuckets are part of GCPProjects.

    +
    (GCPProject)-[RESOURCE]->(GCPBucket)
    +
    +
    +
  • +
  • GCPBuckets can be labelled with GCPBucketLabels.

    +
    (GCPBucket)<-[LABELLED]-(GCPBucketLabels)
    +
    +
    +
  • +
+
+
+
+

GCPDNSZone

+

Representation of a GCP DNS Zone.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

created_at

The date and time the zone was created

description

An optional description of the zone

dns_name

The DNS name of this managed zone, for instance “example.com.”.

firstseen

Timestamp of when a sync job first discovered this node

id

Unique identifier

name

The name of the zone

nameservers

Virtual name servers the zone is delegated to

visibility

The zone’s visibility: public zones are exposed to the Internet, while private zones are visible only to Virtual Private Cloud resources.

+
+

Relationships

+
    +
  • GKEClusters are resources of GCPProjects.

    +
    (GCPProject)-[RESOURCE]->(GCPDNSZone)
    +
    +
    +
  • +
+
+
+
+

Label: GCPBucketLabel

+

Representation of a GCP Storage Bucket Label. This node contains a key-value pair.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the bucket label. Takes the form “GCPBucketLabel_{key}.”

key

The key of the bucket label.

value

The value of the bucket label.

+
    +
  • GCPBuckets can be labeled with GCPBucketLabels.

    +
    (GCPBucket)<-[LABELED]-(GCPBucketLabels)
    +
    +
    +
  • +
+
+
+

GCPInstance

+

Representation of a GCP Instance. Additional references can be found in the official documentation.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The partial resource URI representing this instance. Has the form projects/{project_name}/zones/{zone_name}/instances/{instance_name}.

partial_uri

Same as id above.

self_link

The full resource URI representing this instance. Has the form https://www.googleapis.com/compute/v1/{partial_uri}

instancename

The name of the instance, e.g. “my-instance”

zone_name

The zone that the instance is installed on

hostname

If present, the hostname of the instance

exposed_internet

Set to True with exposed_internet_type = 'direct' if there is an ‘allow’ IPRule attached to one of the instance’s ingress firewalls with the following conditions: The ‘allow’ IpRule allows traffic from one or more TCP ports, and the ‘allow’ IpRule is not superceded by a ‘deny’ IPRule (in GCP, a firewall rule of priority 1 gets applied ahead of a firewall rule of priority 100, and ‘deny’ rules of the same priority are applied ahead of ‘allow’ rules)

status

The GCP Instance Lifecycle state of the instance

+
+

Relationships

+
    +
  • GCPInstances are resources of GCPProjects.

    +
    (GCPProject)-[RESOURCE]->(GCPInstance)
    +
    +
    +
  • +
  • GCPNetworkInterfaces are attached to GCPInstances

    +
    (GCPInstance)-[NETWORK_INTERFACE]->(GCPNetworkInterface)
    +
    +
    +
  • +
  • GCP Instances may be members of one or more GCP VPCs.

    +
       (GCPInstance)-[:MEMBER_OF_GCP_VPC]->(GCPVpc)
    +
    +Also note that this relationship is a shortcut for:
    +
    +
    +
    (GCPInstance)-[:NETWORK_INTERFACE]->(:GCPNetworkInterface)-[:PART_OF_SUBNET]->(GCPSubnet)<-[:RESOURCE]-(GCPVpc)
    +
    +
    +
  • +
  • GCP Instances may have GCP Tags defined on them for use in network firewall routing.

    +
    (GCPInstance)-[:TAGGED]->(GCPNetworkTag)
    +
    +
    +
  • +
  • GCP Firewalls allow ingress to GCP instances.

    +
       (GCPFirewall)-[:FIREWALL_INGRESS]->(GCPInstance)
    +
    +Note that this relationship is a shortcut for:
    +
    +
    +
       (vpc:GCPVpc)<-[MEMBER_OF_GCP_VPC]-(GCPInstance)-[TAGGED]->(GCPNetworkTag)-[TARGET_TAG]-(GCPFirewall{direction: 'INGRESS'})<-[RESOURCE]-(vpc)
    +
    +as well as
    +
    +
    +
    MATCH (fw:GCPFirewall{direction: 'INGRESS', has_target_service_accounts: False}})
    +WHERE NOT (fw)-[TARGET_TAG]->(GCPNetworkTag)
    +MATCH (GCPInstance)-[MEMBER_OF_GCP_VPC]->(GCPVpc)-[RESOURCE]->(fw)
    +
    +
    +
  • +
+
+
+
+

GCPNetworkTag

+

Representation of a Tag defined on a GCP Instance or GCP Firewall. Tags are defined on GCP instances for use in network firewall routing.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

GCP doesn’t define a resource URI for Tags so we define this as {instance resource URI}/tags/{tag value}

tag_id

same as id

value

The actual value of the tag

+
+

Relationships

+
    +
  • GCP Instances can be labeled with tags.

    +
    (GCPInstance)-[:TAGGED]->(GCPNetworkTag)
    +
    +
    +
  • +
  • GCP Firewalls can be labeled with tags to direct traffic to or deny traffic to labeled GCPInstances

    +
    (GCPFirewall)-[:TARGET_TAG]->(GCPNetworkTag)
    +
    +
    +
  • +
  • GCPNetworkTags are defined on a VPC and only have effect on assets in that VPC

    +
    (GCPVpc)-[DEFINED_IN]->(GCPNetworkTag)
    +
    +
    +
  • +
+
+
+
+

GCPVpc

+

Representation of a GCP VPC. In GCP documentation this is also known simply as a “Network” object.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The partial resource URI representing this VPC. Has the form projects/{project_name}/global/networks/{vpc name}.

partial_uri

Same as id

self_link

The full resource URI representing this VPC. Has the form https://www.googleapis.com/compute/v1/{partial_uri}

name

The name of the VPC

project_id

The project ID that this VPC belongs to

auto_create_subnetworks

When set to true, the VPC network is created in “auto” mode. When set to false, the VPC network is created in “custom” mode. An auto mode VPC network starts with one subnet per region. Each subnet has a predetermined range as described in Auto mode VPC network IP ranges.

routing_confg_routing_mode

The network-wide routing mode to use. If set to REGIONAL, this network’s Cloud Routers will only advertise routes with subnets of this network in the same region as the router. If set to GLOBAL, this network’s Cloud Routers will advertise routes with all subnets of this network, across regions.

description

A description for the VPC

+
+

Relationships

+
    +
  • GCPVpcs are part of projects

    +
    (GCPProject)-[RESOURCE]->(GCPVpc)
    +
    +
    +
  • +
  • GCPVpcs contain GCPSubnets

    +
    (GCPVpc)-[RESOURCE]->(GCPSubnet)
    +
    +
    +
  • +
  • GCPSubnets are part of GCP VPCs

    +
    (GCPVpc)-[RESOURCE]->(GCPSubnet)
    +
    +
    +
  • +
  • GCPNetworkTags are defined on a VPC and only have effect on assets in that VPC

    +
    (GCPVpc)-[DEFINED_IN]->(GCPNetworkTag)
    +
    +
    +
  • +
  • GCP Instances may be members of one or more GCP VPCs.

    +
       (GCPInstance)-[:MEMBER_OF_GCP_VPC]->(GCPVpc)
    +
    +Also note that this relationship is a shortcut for:
    +
    +
    +
    (GCPInstance)-[:NETWORK_INTERFACE]->(:GCPNetworkInterface)-[:PART_OF_SUBNET]->(GCPSubnet)<-[:RESOURCE]-(GCPVpc)
    +
    +
    +
  • +
+
+
+
+

GCPNetworkInterface

+

Representation of a GCP Instance’s network interface (scroll down to the fields on “networkInterface”).

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

A partial resource URI representing this network interface. Note: GCP does not define a partial resource URI for network interfaces, so we create one so we can uniquely identify GCP network interfaces. Has the form projects/{project_name}/zones/{zone_name}/instances/{instance_name}/networkinterfaces/{network interface name}.

nic_id

Same as id

name

The name of the network interface

private_ip

The private IP address of this network interface. This IP is valid on the network interface’s VPC.

+
+

Relationships

+
    +
  • GCPNetworkInterfaces are attached to GCPInstances

    +
    (GCPInstance)-[NETWORK_INTERFACE]->(GCPNetworkInterface)
    +
    +
    +
  • +
  • GCPNetworkInterfaces are connected to GCPSubnets

    +
    (GCPNetworkInterface)-[PART_OF_SUBNET]->(GCPSubnet)
    +
    +
    +
  • +
  • GCPNetworkInterfaces have GCPNicAccessConfig objects defined on them

    +
    (GCPNetworkInterface)-[RESOURCE]->(GCPNicAccessConfig)
    +
    +
    +
  • +
+
+
+
+

GCPNicAccessConfig

+

Representation of the AccessConfig object on a GCP Instance’s network interface (scroll down to the fields on “networkInterface”).

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

A partial resource URI representing this AccessConfig. Note: GCP does not define a partial resource URI for AccessConfigs, so we create one so we can uniquely identify GCP network interface access configs. Has the form projects/{project_name}/zones/{zone_name}/instances/{instance_name}/networkinterfaces/{network interface name}/accessconfigs/{access config type}.

partial_uri

Same as id

type

The type of configuration. GCP docs say: “The default and only option is ONE_TO_ONE_NAT.”

name

The name of this access configuration. The default and recommended name is External NAT, but you can use any arbitrary string, such as My external IP or Network Access.

public_ip

The external IP associated with this instance

set_public_ptr

Specifies whether a public DNS ‘PTR’ record should be created to map the external IP address of the instance to a DNS domain name.

public_ptr_domain_name

The DNS domain name for the public PTR record. You can set this field only if the setPublicPtr field is enabled.

network_tier

This signifies the networking tier used for configuring this access configuration and can only take the following values: PREMIUM, STANDARD.

+
+

Relationships

+
    +
  • GCPNetworkInterfaces have GCPNicAccessConfig objects defined on them

    +
    (GCPNetworkInterface)-[RESOURCE]->(GCPNicAccessConfig)
    +
    +
    +
  • +
+
+
+
+

GCPRecordSet

+

Representation of a GCP Resource Record Set.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

data

Data contained in the record

firstseen

Timestamp of when a sync job first discovered this node

id

Same as name

name

The name of the Resource Record Set

type

The identifier of a supported record type. See the list of Supported DNS record types.

ttl

Number of seconds that this ResourceRecordSet can be cached by resolvers.

+
+

Relationships

+
    +
  • GCPRecordSets are records of GCPDNSZones.

    +
    (GCPDNSZone)-[HAS_RECORD]->(GCPRecordSet)
    +
    +
    +
  • +
+
+
+
+

GCPSubnet

+

Representation of a GCP Subnetwork.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

A partial resource URI representing this Subnet. Has the form projects/{project}/regions/{region}/subnetworks/{subnet name}.

partial_uri

Same as id

self_link

The full resource URI representing this subnet. Has the form https://www.googleapis.com/compute/v1/{partial_uri}

project_id

The project ID that this Subnet belongs to

name

The name of this Subnet

region

The region of this Subnet

gateway_address

Gateway IP address of this Subnet

ip_cidr_range

The CIDR range covered by this Subnet

vpc_partial_uri

The partial URI of the VPC that this Subnet is a part of

private_ip_google_access

Whether the VMs in this subnet can access Google services without assigned external IP addresses. This field can be both set at resource creation time and updated using setPrivateIpGoogleAccess.

+
+

Relationships

+
    +
  • GCPSubnets are part of GCP VPCs

    +
    (GCPVpc)-[RESOURCE]->(GCPSubnet)
    +
    +
    +
  • +
  • GCPNetworkInterfaces are connected to GCPSubnets

    +
    (GCPNetworkInterface)-[PART_OF_SUBNET]->(GCPSubnet)
    +
    +
    +
  • +
+
+
+
+

GCPFirewall

+

Representation of a GCP Firewall.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

A partial resource URI representing this Firewall.

partial_uri

Same as id

direction

Either ‘INGRESS’ for inbound or ‘EGRESS’ for outbound

disabled

Whether this firewall object is disabled

priority

The priority of this firewall rule from 1 (apply this first)-65535 (apply this last)

self_link

The full resource URI to this firewall

has_target_service_accounts

Set to True if this Firewall has target service accounts defined. This field is currently a placeholder for future functionality to add GCP IAM objects to Cartography. If True, this firewall rule will only apply to GCP instances that use the specified target service account.

+
+

Relationships

+
    +
  • Firewalls belong to VPCs

    +
    (GCPVpc)-[RESOURCE]->(GCPFirewall)
    +
    +
    +
  • +
  • Firewalls define rules that allow traffic

    +
    (GcpIpRule)-[ALLOWED_BY]->(GCPFirewall)
    +
    +
    +
  • +
  • Firewalls define rules that deny traffic

    +
    (GcpIpRule)-[DENIED_BY]->(GCPFirewall)
    +
    +
    +
  • +
  • GCP Firewalls can be labeled with tags to direct traffic to or deny traffic to labeled GCPInstances

    +
    (GCPFirewall)-[:TARGET_TAG]->(GCPNetworkTag)
    +
    +
    +
  • +
  • GCP Firewalls allow ingress to GCP instances.

    +
       (GCPFirewall)-[:FIREWALL_INGRESS]->(GCPInstance)
    +
    +Note that this relationship is a shortcut for:
    +
    +
    +
       (vpc:GCPVpc)<-[MEMBER_OF_GCP_VPC]-(GCPInstance)-[TAGGED]->(GCPNetworkTag)-[TARGET_TAG]-(GCPFirewall{direction: 'INGRESS'})<-[RESOURCE]-(vpc)
    +
    +as well as
    +
    +
    +
    MATCH (fw:GCPFirewall{direction: 'INGRESS', has_target_service_accounts: False}})
    +WHERE NOT (fw)-[TARGET_TAG]->(GCPNetworkTag)
    +MATCH (GCPInstance)-[MEMBER_OF_GCP_VPC]->(GCPVpc)-[RESOURCE]->(fw)
    +
    +
    +
  • +
+
+
+
+

GCPForwardingRule

+

Representation of GCP Forwarding Rules and Global Forwarding Rules.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

A partial resource URI representing this Forwarding Rule

partial_uri

Same as id

ip_address

IP address that this Forwarding Rule serves

ip_protocol

IP protocol to which this rule applies

load_balancing_scheme

Specifies the Forwarding Rule type

name

Name of the Forwarding Rule

network

A partial resource URI of the network this Forwarding Rule belongs to

port_range

Port range used in conjunction with a target resource. Only packets addressed to ports in the specified range will be forwarded to target configured

ports

Ports to forward to a backend service. Only packets addressed to these ports are forwarded to the backend services configured

project_id

The project ID that this Forwarding Rule belongs to

region

The region of this Forwarding Rule

self_link

Server-defined URL for the resource

subnetwork

A partial resource URI of the subnetwork this Forwarding Rule belongs to

target

A partial resource URI of the target resource to receive the traffic

+
+

Relationships

+
    +
  • GCPForwardingRules can be a resource of a GCPVpc.

    +
    (GCPVpc)-[RESOURCE]->(GCPForwardingRule)
    +
    +
    +
  • +
  • GCPForwardingRules can be a resource of a GCPSubnet.

    +
    (GCPSubnet)-[RESOURCE]->(GCPForwardingRule)
    +
    +
    +
  • +
+
+
+
+

GKECluster

+

Representation of a GCP GKE Cluster.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

basic_auth

Set to True if both masterauth_username and masterauth_password are set

created_at

The date and time the cluster was created

cluster_ipv4cidr

The IP address range of the container pods in the cluster

current_master_version

The current software version of the master endpoint

database_encryption

Configuration of etcd encryption

description

An optional description of the cluster

endpoint

The IP address of the cluster’s master endpoint. The endpoint can be accessed from the internet at https://username:password@endpoint/

exposed_internet

Set to True if at least among private_nodes, private_endpoint_enabled, or master_authorized_networks are disabled

firstseen

Timestamp of when a sync job first discovered this node

id

Same as self_link

initial_version

The initial Kubernetes version for the cluster

location

The name of the Google Compute Engine zone or region in which the cluster resides

logging_service

The logging service used to write logs. Available options: logging.googleapis.com/kubernetes, logging.googleapis.com, none

master_authorized_networks

If enabled, it disallows all external traffic to access Kubernetes master through HTTPS except traffic from the given CIDR blocks, Google Compute Engine Public IPs and Google Prod IPs

masterauth_username

The username to use for HTTP basic authentication to the master endpoint. For clusters v1.6.0 and later, basic authentication can be disabled by leaving username unspecified (or setting it to the empty string)

masterauth_password

The password to use for HTTP basic authentication to the master endpoint. If a password is provided for cluster creation, username must be non-empty

monitoring_service

The monitoring service used to write metrics. Available options: monitoring.googleapis.com/kubernetes, monitoring.googleapis.com, none

name

The name of the cluster

network

The name of the Google Compute Engine network to which the cluster is connected

network_policy

Set to True if a network policy provider has been enabled

private_endpoint_enabled

Whether the master’s internal IP address is used as the cluster endpoint

private_endpoint

The internal IP address of the cluster’s master endpoint

private_nodes

If enabled, all nodes are given only private addresses and communicate with the master via private networking

public_endpoint

The external IP address of the cluster’s master endpoint

self_link

Server-defined URL for the resource

services_ipv4cidr

The IP address range of the Kubernetes services in the cluster

shielded_nodes

Whether Shielded Nodes are enabled

status

The current status of the cluster

subnetwork

The name of the Google Compute Engine subnetwork to which the cluster is connected

zone

The name of the Google Compute Engine zone in which the cluster resides

+
+

Relationships

+
    +
  • GKEClusters are resources of GCPProjects.

    +
    (GCPProject)-[RESOURCE]->(GKECluster)
    +
    +
    +
  • +
+
+
+
+

IpRule::IpPermissionInbound::GCPIpRule

+

An IpPermissionInbound node is a specific type of IpRule. It represents a generic inbound IP-based rules. The creation of this node is currently derived from ingesting AWS EC2 Security Group rules.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

ruleid

{firewall_partial_uri}/{rule_type}/{port_range}{protocol}

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

protocol

The protocol this rule applies to

fromport

Lowest port in the range defined by this rule

toport

Highest port in the range defined by this rule

+
+

Relationships

+
    +
  • GCP Firewall rules are defined on IpRange objects.

    +
    (GCPIpRule, IpRule, IpPermissionInbound)<-[MEMBER_OF_IP_RULE)-(:IpRange)
    +
    +
    +
  • +
  • Firewalls define rules that allow traffic

    +
    (GcpIpRule)-[ALLOWED_BY]->(GCPFirewall)
    +
    +
    +
  • +
  • Firewalls define rules that deny traffic

    +
    (GcpIpRule)-[DENIED_BY]->(GCPFirewall)
    +
    +
    +
  • +
+
+
+
+

IpRange

+

Representation of an IP range or subnet.

+ ++++ + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

CIDR notation for the IP range. E.g. “0.0.0.0/0” for the whole internet.

+
+

Relationships

+
    +
  • GCP Firewall rules are defined on IpRange objects.

    +
    (GCPIpRule, IpRule, IpPermissionInbound)<-[MEMBER_OF_IP_RULE)-(:IpRange)
    +
    +
    +
  • +
+
+
+
+
+

Github Schema

+
+

GitHubRepository

+

Representation of a single GitHubRepository (repo) repository object. This node contains all data unique to the repo.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first created this node

lastupdated

Timestamp of the last time the node was updated

id

The GitHub repo id. These are not unique across GitHub instances, so are prepended with the API URL the id applies to

createdat

GitHub timestamp from when the repo was created

name

Name of the repo

fullname

Name of the organization and repo together

description

Text describing the repo

primarylanguage

The primary language used in the repo

homepage

The website used as a homepage for project information

defaultbranch

The default branch used by the repo, typically master

defaultbranchid

The unique identifier of the default branch

private

True if repo is private

disabled

True if repo is disabled

archived

True if repo is archived

locked

True if repo is locked

giturl

URL used to access the repo from git commandline

url

Web URL for viewing the repo

sshurl

URL for access the repo via SSH

updatedat

GitHub timestamp for last time repo was modified

+
+

Relationships

+
    +
  • GitHubUsers or GitHubOrganizations own GitHubRepositories.

    +
    (GitHubUser)-[OWNER]->(GitHubRepository)
    +(GitHubOrganization)-[OWNER]->(GitHubRepository)
    +
    +
    +
  • +
  • GitHubRepositories in an organization can have outside collaborators with different permissions, including ADMIN, +WRITE, MAINTAIN, TRIAGE, and READ (Reference).

    +
    (GitHubUser)-[:OUTSIDE_COLLAB_{ACTION}]->(GitHubRepository)
    +
    +
    +
  • +
  • GitHubRepositories use ProgrammingLanguages

    +
    (GitHubRepository)-[:LANGUAGE]->(ProgrammingLanguage)
    +
    +
    +
  • +
  • GitHubRepositories have GitHubBranches

    +
    (GitHubRepository)-[:BRANCH]->(GitHubBranch)
    +
    +
    +
  • +
  • GitHubTeams can have various levels of access to GitHubRepositories.

    +
    (GitHubTeam)-[ADMIN|READ|WRITE|TRIAGE|MAINTAIN]->(GitHubRepository)
    +
    +
    +
  • +
+
+
+
+

GitHubOrganization

+

Representation of a single GitHubOrganization organization object. This node contains minimal data for the GitHub Organization.

+ ++++ + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first created this node

lastupdated

Timestamp of the last time the node was updated

id

The URL of the GitHub organization

username

Name of the organization

+
+

Relationships

+
    +
  • GitHubOrganizations own GitHubRepositories.

    +
    (GitHubOrganization)-[OWNER]->(GitHubRepository)
    +
    +
    +
  • +
  • GitHubTeams are resources under GitHubOrganizations

    +
    (GitHubOrganization)-[RESOURCE]->(GitHubTeam)
    +
    +
    +
  • +
+
+
+
+

GitHubTeam

+

A GitHubTeam organization object.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first created this node

lastupdated

Timestamp of the last time the node was updated

id

The URL of the GitHub Team

name

The name (a.k.a URL slug) of the GitHub Team

description

Description of the GitHub team

+
+

Relationships

+
    +
  • GitHubTeams can have various levels of access to GitHubRepositories.

    +
    (GitHubTeam)-[ADMIN|READ|WRITE|TRIAGE|MAINTAIN]->(GitHubRepository)
    +
    +
    +
  • +
  • GitHubTeams are resources under GitHubOrganizations

    +
    (GitHubOrganization)-[RESOURCE]->(GitHubTeam)
    +
    +
    +
  • +
+
+
+
+

GitHubUser

+

Representation of a single GitHubUser user object. This node contains minimal data for the GitHub User.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first created this node

lastupdated

Timestamp of the last time the node was updated

id

The URL of the GitHub user

username

Name of the user

fullname

The full name

has_2fa_enabled

Whether the user has 2-factor authentication enabled

role

Either ‘ADMIN’ (denoting that the user is an owner of a Github organization) or ‘MEMBER’

is_site_admin

Whether the user is a site admin

permission

Only present if the user is an outside collaborator of this repo.

+

permission is either ADMIN, MAINTAIN, READ, TRIAGE, or WRITE (ref). +| email | The user’s publicly visible profile email. +| company | The user’s public profile company.

+
+

Relationships

+
    +
  • GitHubUsers own GitHubRepositories.

    +
    (GitHubUser)-[OWNER]->(GitHubRepository)
    +
    +
    +
  • +
  • GitHubRepositories in an organization can have outside collaborators with different permissions, including ADMIN, +WRITE, MAINTAIN, TRIAGE, and READ (Reference).

    +
    (GitHubUser)-[:OUTSIDE_COLLAB_{ACTION}]->(GitHubRepository)
    +
    +
    +
  • +
+
+
+
+

GitHubBranch

+

Representation of a single GitHubBranch ref object. This node contains minimal data for a repository branch.

+ ++++ + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first created this node

lastupdated

Timestamp of the last time the node was updated

id

The GitHub branch id. These are not unique across GitHub instances, so are prepended with the API URL the id applies to

name

Name of the branch

+
+

Relationships

+
    +
  • GitHubRepositories have GitHubBranches.

    +
    (GitHubBranch)<-[BRANCH]-(GitHubRepository)
    +
    +
    +
  • +
+
+
+
+

ProgrammingLanguage

+

Representation of a single Programming Language language object. This node contains programming language information.

+ ++++ + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first created this node

lastupdated

Timestamp of the last time the node was updated

id

Language ids need not be tracked across instances, so defaults to the name

name

Name of the language

+
+

Relationships

+
    +
  • GitHubRepositories use ProgrammingLanguages.

    +
    (ProgrammingLanguage)<-[LANGUAGE]-(GitHubRepository)
    +
    +
    +
  • +
+
+
+
+

Dependency::PythonLibrary

+

Representation of a Python library as listed in a requirements.txt +or setup.cfg file. +Within a setup.cfg file, cartography will load everything from install_requires, setup_requires, and extras_require.

+ ++++ + + + + + + + + + + + + + + + + +

Field

Description

id

The canonicalized name of the library. If the library was pinned in a requirements file using the == operator, then id has the form {canonical name}|{pinned_version}.

name

The canonicalized name of the library.

version

The exact version of the library. This field is only present if the library was pinned in a requirements file using the == operator.

+
+

Relationships

+
    +
  • Software on Github repos can import Python libraries by optionally specifying a version number.

    +
    (GitHubRepository)-[:REQUIRES{specifier}]->(PythonLibrary)
    +
    +
    +
      +
    • specifier: A string describing this library’s version e.g. “<4.0,>=3.0” or “==1.0.2”. This field is only present on the :REQUIRES edge if the repo’s requirements file provided a version pin.

    • +
    +
  • +
+
+
+
+
+

GSuite Schema

+
+

GSuiteUser

+

Reference: +https://developers.google.com/admin-sdk/directory/v1/reference/users#resource

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

id

The unique ID for the user as a string. A user id can be used as a user request URI’s userKey

user_id

duplicate of id.

agreed_to_terms

This property is true if the user has completed an initial login and accepted the Terms of Service agreement.

change_password_at_next_login

Indicates if the user is forced to change their password at next login. This setting doesn’t apply when the user signs in via a third-party identity provider.

creation_time

The time the user’s account was created. The value is in ISO 8601 date and time format. The time is the complete date plus hours, minutes, and seconds in the form YYYY-MM-DDThh:mm:ssTZD. For example, 2010-04-05T17:30:04+01:00.

customer_id

The customer ID to retrieve all account users. You can use the alias my_customer to represent your account’s customerId. As a reseller administrator, you can use the resold customer account’s customerId. To get a customerId, use the account’s primary domain in the domain parameter of a users.list request.

etag

ETag of the resource

include_in_global_address_list

Indicates if the user’s profile is visible in the G Suite global address list when the contact sharing feature is enabled for the domain. For more information about excluding user profiles, see the administration help center.

ip_whitelisted

If true, the user’s IP address is white listed.

is_admin

Indicates a user with super admininistrator privileges. The isAdmin property can only be edited in the Make a user an administrator operation (makeAdmin method). If edited in the user insert or update methods, the edit is ignored by the API service.

is_delegated_admin

Indicates if the user is a delegated administrator. Delegated administrators are supported by the API but cannot create or undelete users, or make users administrators. These requests are ignored by the API service. Roles and privileges for administrators are assigned using the Admin console.

is_enforced_in_2_sv

Is 2-step verification enforced (Read-only)

is_enrolled_in_2_sv

Is enrolled in 2-step verification (Read-only)

is_mailbox_setup

Indicates if the user’s Google mailbox is created. This property is only applicable if the user has been assigned a Gmail license.

kind

The type of the API resource. For Users resources, the value is admin#directory#user.

last_login_time

The last time the user logged into the user’s account. The value is in ISO 8601 date and time format. The time is the complete date plus hours, minutes, and seconds in the form YYYY-MM-DDThh:mm:ssTZD. For example, 2010-04-05T17:30:04+01:00.

name

First name + Last name

family_name

The user’s last name. Required when creating a user account.

given_name

The user’s first name. Required when creating a user account.

org_unit_path

The full path of the parent organization associated with the user. If the parent organization is the top-level, it is represented as a forward slash (/).

primary_email

The user’s primary email address. This property is required in a request to create a user account. The primaryEmail must be unique and cannot be an alias of another user.

suspended

Indicates if user is suspended

thumbnail_photo_etag

ETag of the user’s photo

thumbnail_photo_url

Photo Url of the user

lastupdated

Timestamp of when a sync job last updated this node

firstseen

Timestamp of when a sync job first discovered this node

+
+

Relationships

+
    +
  • GSuiteUser is an identity for a Human

    +
    (Human)-[IDENTITY_GSUITE]->(GSuiteUser)
    +
    +
    +
  • +
+
+
+
+

GSuiteGroup

+

Reference: +https://developers.google.com/admin-sdk/directory/v1/reference/groups

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

id

The unique ID of a group. A group id can be used as a group request URI’s groupKey.

admin_created

Value is true if this group was created by an administrator rather than a user.

description

An extended description to help users determine the purpose of a group. For example, you can include information about who should join the group, the types of messages to send to the group, links to FAQs about the group, or related groups. Maximum length is 4,096 characters.

direct_members_count

The number of users that are direct members of the group. If a group is a member (child) of this group (the parent), members of the child group are not counted in the directMembersCount property of the parent group

email

The group’s email address. If your account has multiple domains, select the appropriate domain for the email address. The email must be unique. This property is required when creating a group. Group email addresses are subject to the same character usage rules as usernames, see the administration help center for the details.

etag

ETag of the resource

kind

The type of the API resource. For Groups resources, the value is admin#directory#group.

name

The group’s display name.

lastupdated

Timestamp of when a sync job last updated this node

firstseen

Timestamp of when a sync job first discovered this node

+
+
+
+

Jamf Schema

+
+

JamfComputerGroup

+

Representation of a Jamf computer group.

+ ++++ + + + + + + + + + + + + + + + + +

Field

Description

id

The group id

name

The friendly name of the group

is_smart

Whether the group is smart

+
+

Relationships

+
    +
  • Coming soon!

  • +
+
+
+
+
+

Kubernetes Schema

+
+

KubernetesCluster

+

Representation of a Kubernetes Cluster.

+ ++++ + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Identifier for the cluster i.e. UID of kube-system namespace

name

Name assigned to the cluster which is derived from kubeconfig context

+
+

Relationships

+
    +
  • KubernetesCluster has KubernetesNamespaces.

    +
    (KubernetesCluster)-[HAS_NAMESPACE]->(KubernetesNamespace)
    +
    +
    +
  • +
  • KubernetesCluster can have KubernetesPods.

    +
    (KubernetesCluster)-[HAS_POD]->(KubernetesPod)
    +
    +
    +
  • +
+
+
+
+

KubernetesNamespace

+

Representation of a Kubernetes Namespace.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

UID of the kubernetes namespace

name

Name of the kubernetes namespace

created_at

Timestamp of the creation time of the kubernetes namespace

deleted_at

Timestamp of the deletion time of the kubernetes namespace

+
+

Relationships

+
    +
  • KubernetesNamespace can have KubernetesPods.

    +
    (KubernetesNamespace)-[HAS_POD]->(KubernetesPod)
    +
    +
    +
  • +
  • KubernetesNamespace can have KubernetesServices.

    +
    (KubernetesNamespace)-[HAS_SERVICE]->(KubernetesService)
    +
    +
    +
  • +
  • KubernetesNamespace can have KubernetesSecrets.

    +
    (KubernetesNamespace)-[HAS_SECRET]->(KubernetesSecret)
    +
    +
    +
  • +
+
+
+
+

KubernetesPod

+

Representation of a Kubernetes Pod.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

UID of the kubernetes pod

name

Name of the kubernetes pod

status_phase

The phase of a Pod is a simple, high-level summary of where the Pod is in its lifecycle.

created_at

Timestamp of the creation time of the kubernetes pod

deleted_at

Timestamp of the deletion time of the kubernetes pod

+
+

Relationships

+
    +
  • KubernetesPod has KubernetesContainers.

    +
    (KubernetesPod)-[HAS_CONTAINER]->(KubernetesContainer)
    +
    +
    +
  • +
+
+
+
+

KubernetesContainer

+

Representation of a Kubernetes Container.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

Identifier for the container which is derived from the UID of pod and the name of container

name

Name of the container in kubernetes pod

image

Docker image used in the container

status_image_id

ImageID of the container’s image.

status_image_sha

The SHA portion of the status_image_id

status_ready

Specifies whether the container has passed its readiness probe.

status_started

Specifies whether the container has passed its startup probe.

statys_state

State of the container (running, terminated, waiting)

+
+

Relationships

+
    +
  • KubernetesPod has KubernetesContainers.

    +
    (KubernetesPod)-[HAS_CONTAINER]->(KubernetesContainer)
    +
    +
    +
  • +
+
+
+
+

KubernetesService

+

Representation of a Kubernetes Service.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

UID of the kubernetes service

name

Name of the kubernetes service

created_at

Timestamp of the creation time of the kubernetes service

deleted_at

Timestamp of the deletion time of the kubernetes service

type

Type of kubernetes service e.g. ClusterIP

load_balancer_ip

IP of the load balancer when service type is LoadBalancer

ingress_host

Hostname of the ingress endpoint, if any

ingress_ip

IP of the ingress endpoint, if any

+
+

Relationships

+
    +
  • KubernetesService can serve KubernetesPods.

    +
    (KubernetesService)-[SERVES_POD]->(KubernetesPod)
    +
    +
    +
  • +
+
+
+
+

KubernetesSecret

+

Representation of a Kubernetes Secret.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

UID of the kubernetes secret

name

Name of the kubernetes secret

created_at

Timestamp of the creation time of the kubernetes secret

deleted_at

Timestamp of the deletion time of the kubernetes secret

type

Type of kubernetes secret e.g. Opaque

+
+

Relationships

+
    +
  • KubernetesNamespace can have KubernetesSecrets.

    +
    (KubernetesNamespace)-[HAS_SECRET]->(KubernetesSecret)
    +
    +
    +
  • +
+
+
+
+
+

Okta Schema

+
+

OktaOrganization

+

Representation of an Okta Organization.

+ ++++ + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The name of the Okta Organization, e.g. “lyft”

name

The name of the Okta Organization, e.g. “lyft”

+
+

Relationships

+
    +
  • An OktaOrganization contains OktaUsers

    +
    (OktaOrganization)-[RESOURCE]->(OktaUser)
    +
    +
    +
  • +
  • An OktaOrganization contains OktaGroups.

    +
    (OktaOrganization)-[RESOURCE]->(OktaGroup)
    +
    +
    +
  • +
  • An OktaOrganization contains OktaApplications

    +
    (OktaOrganization)-[RESOURCE]->(OktaApplication)
    +
    +
    +
  • +
  • An OktaOrganization has OktaTrustedOrigins

    +
    (OktaOrganization)-[RESOURCE]->(OktaTrustedOrigin)
    +
    +
    +
  • +
  • An OktaOrganization has OktaAdministrationRoles

    +
    (OktaOrganization)-[RESOURCE]->(OktaAdministrationRole)
    +
    +
    +
  • +
+
+
+
+

OktaUser

+

Representation of an Okta User.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

id

user id

first_name

user first name

last_name

user last name

login

user usernmae used to login (usually email)

email

user email

second_email

user secondary email

mobile_phone

user mobile phone

created

date and time of creation

activated

date and time of activation

status_changed

date and time of the last state change

last_login

date and time of last login

okta_last_updated

date and time of last user property changes

password_changed

date and time of last password change

transition_to_status

date and time of last state transition change

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

+
+

Relationships

+
    +
  • An OktaOrganization contains OktaUsers

    +
    (OktaUser)<-[RESOURCE]->(OktaOrganization)
    +
    +
    +
  • +
  • OktaUsers are assigned OktaApplication

    +
    (OktaUser)-[APPLICATION]->(OktaApplication)
    +
    +
    +
  • +
  • OktaUser is an identity for a Human

    +
    (OktaUser)<-[IDENTITY_OKTA]-(Human)
    +
    +
    +
  • +
  • An OktaUser can be a member of an OktaGroup

    +
    (OktaUser)-[MEMBER_OF_OKTA_GROUP]->(OktaGroup)
    +
    +
    +
  • +
  • An OktaUser can be a member of an OktaAdministrationRole

    +
    (OktaUser)-[MEMBER_OF_OKTA_ROLE]->(OktaAdministrationRole)
    +
    +
    +
  • +
  • OktaUsers can have authentication factors

    +
    (OktaUser)-[FACTOR]->(OktaUserFactor)
    +
    +
    +
  • +
+
+
+
+

OktaGroup

+

Representation of an Okta Group.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

id

application id

name

group name

description

group description

sam_account_name

windows SAM account name mapped

dn

group dn

windows_domain_qualified_name

windows domain name

external_id

group foreign id

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

+
+

Relationships

+
    +
  • OktaOrganizations contain OktaGroups

    +
    (OktaGroup)<-[RESOURCE]->(OktaOrganizations)
    +
    +
    +
  • +
  • OktaApplications can be assigned to OktaGroups

    +
    (OktaGroup)-[APPLICATION]->(OktaApplication)
    +
    +
    +
  • +
  • An OktaUser can be a member of an OktaGroup

    +
    (OktaUser)-[MEMBER_OF_OKTA_GROUP]->(OktaGroup)
    +
    +
    +
  • +
  • An OktaGroup can be a member of an OktaAdministrationRole

    +
    (OktaGroup)-[MEMBER_OF_OKTA_ROLE]->(OktaAdministrationRole)
    +
    +
    +
  • +
+
+
+
+

OktaApplication

+

Representation of an Okta Application.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

id

application id

name

application name

label

application label

created

application creation date

okta_last_updated

date and time of last application property changes

status

application status

activated

application activation state

features

application features

sign_on_mode

application signon mode

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

+
+

Relationships

+
    +
  • OktaApplication is a resource of an OktaOrganization

    +
    (OktaApplication)<-[RESOURCE]->(OktaOrganization)
    +
    +
    +
      +
    • OktaGroups can be assigned OktaApplications

    • +
    +
    (OktaGroup)-[APPLICATION]->(OktaApplication)
    +
    +
    +
      +
    • OktaUsers are assigned OktaApplications

    • +
    +
    (OktaUser)-[APPLICATION]->(OktaApplication)
    +
    +
    +
      +
    • OktaApplications have ReplyUris

    • +
    +
    (ReplyUri)-[REPLYURI]->(OktaApplication)
    +
    +
    +
  • +
+
+
+
+

OktaUserFactor

+

Representation of Okta User authentication Factors.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

id

factor id

factor_type

factor type

provider

factor provider

status

factor status

created

factor creation date and time

okta_last_updated

date and time of last property changes

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

+
+

Relationships

+
    +
  • OktaUsers can have authentication Factors

    +
    (OktaUser)-[FACTOR]->(OktaUserFactor)
    +
    +
    +
  • +
+
+
+
+

OktaTrustedOrigin

+

Representation of an Okta Trusted Origin for login/logout or recovery operations.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

id

trusted origin id

name

name

scopes

array of scope

status

status

created

date & time of creation in okta

create_by

id of user who created the trusted origin

okta_last_updated

date and time of last property changes

okta_last_updated_by

id of user who last updated the trusted origin

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

+
+

Relationships

+
    +
  • An OktaOrganization has OktaTrustedOrigins.

    +
    (OktaOrganization)-[RESOURCE]->(OktaTrustedOrigin)
    +
    +
    +
  • +
+
+
+
+

OktaAdministrationRole

+

Representation of an Okta Administration Role.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

id

role id mapped to the type

type

role type

label

role label

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

+
+

Relationships

+
    +
  • OktaUsers can be members of OktaAdministrationRoles

    +
    (OktaUser)-[MEMBER_OF_OKTA_ROLE]->(OktaAdministrationRole)
    +
    +
    +
  • +
  • An OktaGroup can be a member of an OktaAdministrationRolee

    +
    (OktaGroup)-[MEMBER_OF_OKTA_ROLE]->(OktaAdministrationRole)
    +
    +
    +
      +
    • An OktaOrganization contains OktaAdministrationRoles

      +
      (OktaOrganization)-[RESOURCE]->(OktaAdministrationRole)
      +
      +
      +
    • +
    +
  • +
+
+
+
+

Reply Uri

+

Representation of Okta Application ReplyUri.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

id

uri the app can send the reply to

uri

uri the app can send the reply to

valid

is the DNS of the reply uri valid. Invalid replyuris can lead to oath phishing

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

+
+

Relationships

+
    +
  • OktaApplications have ReplyUris

    +
    (ReplyUri)-[REPLYURI]->(OktaApplication)
    +
    +
    +
  • +
+
+
+
+
+

Pagerduty Schema

+
+

PagerDutyEscalationPolicy

+

Representation of a PagerDuty Escalation Policy

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the escalation policy

html_url

the API show URL at which the object is accessible

type

The type of this pagerduty object (escalation_policy)

summary

A short-form, server-generated string that provides succinct, important information about an object suitable for primary labeling of an entity in a client. In many cases, this will be identical to name, though it is not intended to be an identifier.

on_call_handoff_notifications

Determines how on call handoff notifications will be sent for users on the escalation policy. Defaults to “if_has_services”.

name

The name of the escalation policy.

num_loops

The number of times the escalation policy will repeat after reaching the end of its escalation.

+
+

Relationships

+
    +
  • A PagerDutyEscalationPolicy has PagerDutyEscalationPolicyRules

    +
    (PagerDutyEscalationPolicy)-[HAS\_RULE]->(PagerDutyEscalationPolicyRule)
    +
    +
    +
  • +
  • A PagerDutyEscalationPolicy is associated with PagerDutyUsers

    +
    (PagerDutyEscalationPolicy)-[ASSOCIATED\_WITH]->(PagerDutyUser)
    +
    +
    +
  • +
  • A PagerDutyEscalationPolicy is associated with PagerDutySchedules

    +
    (PagerDutyEscalationPolicy)-[ASSOCIATED\_WITH]->(PagerDutySchedule)
    +
    +
    +
  • +
  • A PagerDutyEscalationPolicy is associated with PagerDutyServices

    +
    (PagerDutyEscalationPolicy)-[ASSOCIATED\_WITH]->(PagerDutyService)
    +
    +
    +
  • +
  • A PagerDutyEscalationPolicy is associated with PagerDutyTeams

    +
    (PagerDutyEscalationPolicy)-[ASSOCIATED\_WITH]->(PagerDutyTeam)
    +
    +
    +
  • +
+
+
+
+

PagerDutySchedule

+

Representation of a PagerDuty Schedule

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the schedule

html_url

the API show URL at which the object is accessible

type

The type of this pagerduty object (schedule)

summary

A short-form, server-generated string that provides succinct, important information about an object suitable for primary labeling of an entity in a client. In many cases, this will be identical to name, though it is not intended to be an identifier.

name

The name of the schedule.

time_zone

The time zone of the schedule

description

The description of the schedule

+
+

Relationships

+
    +
  • A PagerDutySchedule has PagerDutyScheduleLayers

    +
    (PagerDutySchedule)-[HAS\_LAYER]->(PagerDutyScheduleLayer)
    +
    +
    +
  • +
+
+
+
+

PagerDutyScheduleLayer

+

Representation of a layer in a PagerDuty Schedule

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the schedule layer

schedule_id

The ID of the schedule this layer is attached to.

start

The start time of this layer

end

The end time of this layer. If null, the layer does not end.

rotation_virtual_start

The effective start time of the layer. This can be before the start time of the schedule.

rotation_turn_length_seconds

The duration of each on-call shift in seconds.

+
+

Relationships

+

No relationships originating from PagerDutyScheduleLayer

+
+
+
+

PagerDutyService

+

Representation of a PagerDuty Service

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the service

html_url

the API show URL at which the object is accessible

type

The type of this pagerduty object (service)

summary

A short-form, server-generated string that provides succinct, important information about an object suitable for primary labeling of an entity in a client. In many cases, this will be identical to name, though it is not intended to be an identifier.

name

The name of this service

description

The user-provided description of the service.

auto_resolve_timeout

Time in seconds that an incident is automatically resolved if left open for that long. Value is null if the feature is disabled. Value must not be negative. Setting this field to 0, null (or unset in POST request) will disable the feature.

acknowledgement_timeout

Time in seconds that an incident changes to the Triggered State after being Acknowledged. Value is null if the feature is disabled. Value must not be negative. Setting this field to 0, null (or unset in POST request) will disable the feature.

created_at

The date/time when this service was created

status

The current state of the Service.

alert_creation

Whether a service creates only incidents, or both alerts and incidents. A service must create alerts in order to enable incident merging.

alert_grouping_parameters_type

The type of Alert Grouping.

incident_urgency_rule_type

The type of incident urgency: whether it’s constant, or it’s dependent on the support hours.

incident_urgency_rule_during_support_hours_type

The type of incident urgency: whether it’s constant, or it’s dependent on the support hours.

incident_urgency_rule_during_support_hours_urgency

The incidents’ urgency, if type is constant.

incident_urgency_rule_outside_support_hours_type

The type of incident urgency: whether it’s constant, or it’s dependent on the support hours.

incident_urgency_rule_outside_support_hours_urgency

The incidents’ urgency, if type is constant.

support_hours_type

The type of support hours

support_hours_time_zone

The time zone for the support hours

support_hours_start_time

The support hours’ starting time of day (date portion is ignored)

support_hours_end_time

support_hours_end_time

support_hours_days_of_week

(no description)

+
+

Relationships

+
    +
  • A PagerDutyService has PagerDutyIntegrations

    +
    (PagerDutyService)-[HAS\_INTEGRATION]->(PagerDutyIntegration)
    +
    +
    +
  • +
+
+
+
+

PagerDutyIntegration

+

Representation of a PagerDuty Integration

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the integration

html_url

the API show URL at which the object is accessible

type

The type of this pagerduty object (integration)

summary

A short-form, server-generated string that provides succinct, important information about an object suitable for primary labeling of an entity in a client. In many cases, this will be identical to name, though it is not intended to be an identifier.

name

The name of this integration

created_at

The date/time when this integration was created.

+
+

Relationships

+
    +
  • A PagerDutyIntegration has PagerDutyVendors

    +
    (PagerDutyIntegration)-[HAS\_VENDOR]->(PagerDutyVendor)
    +
    +
    +
  • +
+
+
+
+

PagerDutyTeam

+

Representation of a PagerDuty Team

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the team

html_url

the API show URL at which the object is accessible

type

The type of this pagerduty object (team)

summary

A short-form, server-generated string that provides succinct, important information about an object suitable for primary labeling of an entity in a client. In many cases, this will be identical to name, though it is not intended to be an identifier.

name

The name of the team

description

The description of the team

default_role

(no description, but returned by API)

+
+

Relationships

+
    +
  • A PagerDutyTeam is associated with PagerDutyServices

    +
    (PagerDutyTeam)-[ASSOCIATED\_WITH]->(PagerDutyServices)
    +
    +
    +
  • +
+
+
+
+

PagerDutyUser

+

Representation of a PagerDuty User

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Field

Description

firstseen

Timestamp of when a sync job first discovered this node

lastupdated

Timestamp of the last time the node was updated

id

The ID of the user

html_url

the API show URL at which the object is accessible

type

The type of this pagerduty object (user)

summary

A short-form, server-generated string that provides succinct, important information about an object suitable for primary labeling of an entity in a client. In many cases, this will be identical to name, though it is not intended to be an identifier.

name

The name of the user

email

The user’s email address

time_zone

The preferred time zone name. If null, the account’s time zone will be used.

color

The schedule color

role

The user role. Account must have the read_only_users ability to set a user as a read_only_user or a read_only_limited_user, and must have advanced permissions abilities to set a user as observer or restricted_access.

avatar_url

The URL of the user’s avatar.

description

The user’s bio.

invitation_sent

If true, the user has an outstanding invitation.

job_title

The user’s title

+
+

Relationships

+
    +
  • A PagerDutyUser is a member of PagerDutySchedules

    +
    (PagerDutyUser)-[MEMBER\_OF]->(PagerDutySchedule)
    +
    +
    +
  • +
  • A PagerDutyUser is a member of PagerDutyScheduleLayers

    +
    (PagerDutyUser)-[MEMBER\_OF]->(PagerDutyScheduleLayer)
    +
    +
    +
  • +
  • A PagerDutyUser is a member of PagerDutyTeams

    +
    (PagerDutyUser)-[MEMBER\_OF]->(PagerDutyTeam)
    +
    +
    +
  • +
+
+
+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/usage/tutorial.html b/usage/tutorial.html new file mode 100644 index 0000000000..5d9254ace2 --- /dev/null +++ b/usage/tutorial.html @@ -0,0 +1,860 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Usage Tutorial — cartography documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skip to content +
+ +
+ + +
+ + + + +
+
+ +
+
+
+ +
+
+
+ + +
+
+ +
+

Usage Tutorial

+

Once everything has been installed and synced, you can view the Neo4j web interface at http://localhost:7474. You can view the reference on this here.

+

If you already know Neo4j and just need to know what are the nodes, attributes, and graph relationships for our representation of infrastructure assets, you can view our sample queries. More sample queries are available at https://github.com/marco-lancini/cartography-queries.

+

Otherwise, read on for this handhold-y tutorial filled with examples. Suppose we wanted to find out:

+
+

What RDS instances are installed in my AWS accounts?

+
MATCH (aws:AWSAccount)-[r:RESOURCE]->(rds:RDSInstance)
+return *
+
+
+Visualization of RDS nodes and AWS nodes +

In this query we asked Neo4j to find all [:RESOURCE] relationships from AWSAccounts to RDSInstances, and return the nodes and the :RESOURCE relationships.

+

We will do more interesting things with this result next.

+
+

ℹ️ Protip - customizing your view

+

You can adjust the node colors, sizes, and captions by clicking on the node type at the top of the query. For example, to change the color of an AWSAccount node, first click the “AWSAccount” icon at the top of the view to select the node type

+selecting an AWSAccount node +

and then pick options on the menu that shows up at the bottom of the view like this:

+customizations +
+
+
+

Which RDS instances have encryption turned off?

+
MATCH (a:AWSAccount)-[:RESOURCE]->(rds:RDSInstance{storage_encrypted:false})
+RETURN a.name, rds.id
+
+
+Unencrypted RDS instances +

The results show up in a table because we specified attributes like a.name and rds.id in our return statement (as opposed to having it return *). We used the “{}” notation to have the query only return RDSInstances where storage_encrypted is set to False.

+

If you want to go back to viewing the graph and not a table, simply make sure you don’t have any attributes in your return statement – use return * to return all nodes decorated with a variable label in your MATCH statement, or just return the specific nodes and relationships that you want.

+

Let’s look at some other AWS assets now.

+
+
+

Which EC2 instances are directly exposed to the internet?

+
MATCH (instance:EC2Instance{exposed_internet: true})
+RETURN instance.instanceid, instance.publicdnsname
+
+
+EC2 instances open to the internet +

These instances are open to the internet either through permissive inbound IP permissions defined on their EC2SecurityGroups or their NetworkInterfaces.

+

If you know a lot about AWS, you may have noticed that EC2 instances don’t actually have an exposed_internet field. We’re able to query for this because Cartography performs some data enrichment to add this field to EC2Instance nodes.

+
+
+

Which S3 buckets have a policy granting any level of anonymous access to the bucket?

+
MATCH (s:S3Bucket)
+WHERE s.anonymous_access = true
+RETURN s
+
+
+S3 buckets that allow anon access +

These S3 buckets allow for any user to read data from them anonymously. Similar to the EC2 instance example above, S3 buckets returned by the S3 API don’t actually have an anonymous_access field and this field is added by one of Cartography’s data augmentation steps.

+

A couple of other things to notice: instead of using the “{}” notation to filter for anonymous buckets, we can use SQL-style WHERE clauses. Also, we used the SQL-style AS operator to relabel our output header rows.

+
+
+

How many unencrypted RDS instances do I have in all my AWS accounts?

+

Let’s go back to analyzing RDS instances. In an earlier example we queried for RDS instances that have encryption turned off. We can aggregate this data by AWSAccount with a small change:

+
MATCH (a:AWSAccount)-[:RESOURCE]->(rds:RDSInstance)
+WHERE rds.storage_encrypted = false
+RETURN a.name as AWSAccount, count(rds) as UnencryptedInstances
+
+
+Table of unencrypted RDS instances by AWS account +
+
+

Given a node label, what other node labels can be connected to it?

+

Suppose we wanted to know what other assets can be connected to a DNSRecord. We would ask the graph like this:

+
match (d:DNSRecord)--(n)
+return distinct labels(n);
+
+
+

This says “what are the possible labels for all nodes connected to all DNSRecord nodes d in my graph?” Your answer might look like this:

+
["AWSDNSRecord", "DNSRecord"]
+["AWSDNSZone", "DNSZone"]
+["LoadBalancerV2"]
+["NameServer"]
+["ESDomain"]
+["LoadBalancer"]
+["EC2Instance", "Instance"]
+
+
+

You can then make the path more specific like this:

+
match (d:DNSRecord)--(:EC2Instance)--(n)
+return distinct labels(n);
+
+
+

And then you can continue building your query.

+

We also include full schema docs, but this way of building a query can be faster and more interactive.

+
+
+

Given a node label, what are the possible property names defined on it?

+

We can find what properties are available on an S3Bucket like this:

+
match (n:S3Bucket) return properties(n) limit 1;
+
+
+

The result will look like this:

+
{
+  "bucket_key_enabled": false,
+  "creationdate": "2022-05-10 00:22:52+00:00",
+  "ignore_public_acls": true,
+  "anonymous_access": false,
+  "firstseen": 1652400141863,
+  "block_public_policy": true,
+  "versioning_status": "Enabled",
+  "block_public_acls": true,
+  "anonymous_actions": [],
+  "name": "my-fake-bucket-123",
+  "lastupdated": 1688605272,
+  "encryption_algorithm": "AES256",
+  "default_encryption": true,
+  "id": "my-fake-bucket-123",
+  "arn": "arn:aws:s3:::my-fake-bucket-123",
+  "restrict_public_buckets": false
+}
+
+
+

Our full schema docs describe all possible fields, but listing out properties this way lets you avoid switching between browser tabs.

+
+
+

Learning more

+

If you want to learn more in depth about Neo4j and Cypher queries you can look at this tutorial and see this reference card.

+
+
+

Data Enrichment

+

Cartography adds custom attributes to nodes and relationships to point out security-related items of interest. Unless mentioned otherwise these data augmentation jobs are stored in cartography/data/jobs/analysis. Here is a summary of all of Cartography’s custom attributes.

+
    +
  • exposed_internet indicates whether the asset is accessible to the public internet.

    +
      +
    • Elastic Load Balancers: The exposed_internet flag is set to True when the load balancer’s scheme field is set to internet-facing, and the load balancer has an attached source security group with rules allowing 0.0.0.0/0 ingress on ports or port ranges matching listeners on the load balancer. This scheme indicates that the load balancer has a public DNS name that resolves to a public IP address.

    • +
    • Application Load Balancers: The exposed_internet flag is set to True when the load balancer’s scheme field is set to internet-facing, and the load balancer has an attached security group with rules allowing 0.0.0.0/0 ingress on ports or port ranges matching listeners on the load balancer. This scheme indicates that the load balancer has a public DNS name that resolves to a public IP address.

    • +
    • EC2 instances: The exposed_internet flag on an EC2 instance is set to True when any of following apply:

      +
        +
      • The instance is part of an EC2 security group or is connected to a network interface connected to an EC2 security group that allows connectivity from the 0.0.0.0/0 subnet.

      • +
      • The instance is connected to an Elastic Load Balancer that has its own exposed_internet flag set to True.

      • +
      • The instance is connected to a TargetGroup which is attached to a Listener on an Application Load Balancer (elbv2) that has its own exposed_internet flag set to True.

      • +
      +
    • +
    • ElasticSearch domain: exposed_internet is set to True if the ElasticSearch domain has a policy applied to it that makes it internet-accessible. This policy determination is made by using the policyuniverse library. The code for this augmentation is implemented at cartography.intel.aws.elasticsearch._process_access_policy().

    • +
    +
  • +
  • anonymous_access indicates whether the asset allows access without needing to specify an identity.

    + +
  • +
+
+
+

Extending Cartography with Analysis Jobs

+

You can add your own custom attributes and relationships without writing Python code! Here’s how.

+
+
+

Mapping AWS Access Permissions

+

Cartography can map permissions between IAM Principals and resources in the graph. Here’s how.

+
+
+

Permalinking Bookmarklet

+

You can set up a bookmarklet that lets you quickly get a permalink to a Cartography query. To do so, add a bookmark with the following contents as the URL - make sure to replace neo4j.contoso.com:7474 with your instance of Neo4j:

+
javascript:(() => { const query = document.querySelectorAll('article label span')[0].innerText; if (query === ':server connect') { console.log('no query has been run!'); return; } const searchParams = new URLSearchParams(); searchParams.append('connectURL', 'bolt://neo4j:neo4j@neo4j.contoso.net:7687'); searchParams.append('cmd', 'edit'); searchParams.append('arg', query.replaceAll(/\r /g, '\r')); newURL = `http://neo4j.contoso.net:7474/browser/?${searchParams}`; window.open(newURL, '_blank', 'noopener'); })()
+
+
+

Then, any time you are in the web interface, you can click the bookmarklet to open a new tab with a permalink to your most recently executed query in the URL bar.

+
+
+ + +
+
+
+
+
+ + + + + \ No newline at end of file