From a7803353f03528042f15ade30462b88cb8b2ddc6 Mon Sep 17 00:00:00 2001 From: Ian Lewis Date: Thu, 24 Oct 2019 00:21:45 -0400 Subject: [PATCH 1/9] Added lint-md linter for markdown --- Makefile | 12 +- cloudbuild.yaml | 5 +- content/docs/architecture_guide/_index.md | 2 - content/docs/architecture_guide/overview.md | 6 +- content/docs/architecture_guide/security.md | 24 +- content/docs/community/_index.md | 4 +- content/docs/tutorials/docker.md | 2 +- content/docs/tutorials/kubernetes.md | 8 +- content/docs/user_guide/FAQ.md | 12 +- content/docs/user_guide/checkpoint_restore.md | 34 +- .../docs/user_guide/compatibility/_index.md | 8 +- content/docs/user_guide/debugging.md | 8 +- content/docs/user_guide/install.md | 13 +- content/docs/user_guide/platforms.md | 8 +- content/docs/user_guide/quick_start/_index.md | 6 +- .../docs/user_guide/quick_start/kubernetes.md | 2 +- package-lock.json | 1160 ++++++++++++++++- package.json | 22 +- 18 files changed, 1225 insertions(+), 111 deletions(-) diff --git a/Makefile b/Makefile index 818a2de5e..35b66a803 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,7 @@ GEN_SOURCE = $(wildcard cmd/generate-syscall-docs/*) APP_SOURCE = $(wildcard cmd/gvisor-website/*) # Target Go files, example: public/main.go, public/foo/bar.go. APP_TARGET = $(patsubst cmd/gvisor-website/%,public/%,$(APP_SOURCE)) +CONTENT_SOURCE = $(wildcard content/*) default: website .PHONY: default @@ -63,10 +64,17 @@ compatibility-docs: bin/generate-syscall-docs upstream/gvisor/bazel-bin/runsc/li ./upstream/gvisor/bazel-bin/runsc/linux_amd64_pure_stripped/runsc help syscalls -o json | ./bin/generate-syscall-docs -out ./content/docs/user_guide/compatibility/ .PHONY: compatibility-docs -check: website - docker run -v $(shell pwd)/public:/public gcr.io/gvisor-website/html-proofer:3.10.2 htmlproofer --disable-external --check-html public/static +check: check-markdown check-html .PHONY: check +check-markdown: node_modules $(CONTENT_SOURCE) compatibility-docs + npm run lint-md +.PHONY: check-markdown + +check-html: website + docker run -v $(shell pwd)/public:/public gcr.io/gvisor-website/html-proofer:3.10.2 htmlproofer --disable-external --check-html public/static +.PHONY: check-html + # Run a local content development server. Redirects will not be supported. devserver: all-upstream compatibility-docs $(HUGO) server -FD --port 8080 diff --git a/cloudbuild.yaml b/cloudbuild.yaml index 5cd9e22b2..21965427b 100644 --- a/cloudbuild.yaml +++ b/cloudbuild.yaml @@ -49,7 +49,7 @@ steps: - > ./upstream/gvisor/bazel-bin/runsc/linux_amd64_pure_stripped/runsc help syscalls -o json | ./bin/generate-syscall-docs -out ./content/docs/user_guide/compatibility/ - # Pull npm dependencies for scss + # Pull npm dependencies for scss and lint-md - name: 'gcr.io/cloud-builders/npm' args: ['ci'] # Copy App Engine app files. @@ -59,6 +59,9 @@ steps: - name: 'gcr.io/gvisor-website/hugo:0.53' env: ['HUGO_ENV=production'] args: ["hugo"] + # Test Markdown for issues. + - name: 'gcr.io/cloud-builders/npm' + args: ['run', 'lint-md'] # Test the HTML for issues. - name: 'gcr.io/gvisor-website/html-proofer:3.10.2' args: diff --git a/content/docs/architecture_guide/_index.md b/content/docs/architecture_guide/_index.md index 63842caa4..81c128464 100644 --- a/content/docs/architecture_guide/_index.md +++ b/content/docs/architecture_guide/_index.md @@ -72,8 +72,6 @@ race detector. (The use of Go has its challenges too, and isn't free.) [apparmor]: https://wiki.ubuntu.com/AppArmor [golang]: https://golang.org [kvm]: https://www.linux-kvm.org -[oci]: https://www.opencontainers.org -[sandbox]: https://en.wikipedia.org/wiki/Sandbox_(computer_security) [seccomp]: https://www.kernel.org/doc/Documentation/prctl/seccomp_filter.txt [selinux]: https://selinuxproject.org [uml]: http://user-mode-linux.sourceforge.net/ diff --git a/content/docs/architecture_guide/overview.md b/content/docs/architecture_guide/overview.md index 50ef89c81..c12f9127f 100644 --- a/content/docs/architecture_guide/overview.md +++ b/content/docs/architecture_guide/overview.md @@ -8,12 +8,12 @@ be run. Each sandbox has its own isolated instance of: -* The **Sentry**, A user-space kernel that runs the container and intercepts - and responds to system calls made by the application. +* The **Sentry**, A user-space kernel that runs the container and intercepts + and responds to system calls made by the application. Each container running in the sandbox has its own isolated instance of: -* A **Gofer** which provides file system access to the container. +* A **Gofer** which provides file system access to the container. ![gVisor architecture diagram](../Sentry-Gofer.png "gVisor architecture diagram") diff --git a/content/docs/architecture_guide/security.md b/content/docs/architecture_guide/security.md index 93723727c..5084565e7 100644 --- a/content/docs/architecture_guide/security.md +++ b/content/docs/architecture_guide/security.md @@ -32,9 +32,9 @@ are written in [C][clang], which is well-suited to interfacing with hardware but often prone to security issues. In order to exploit these issues, a typical attack might involve some combination of the following: - 1. Opening or creating some combination of files, sockets or other descriptors. - 1. Passing crafted, malicious arguments, structures or packets. - 1. Racing with multiple threads in order to hit specific code paths. +1. Opening or creating some combination of files, sockets or other descriptors. +1. Passing crafted, malicious arguments, structures or packets. +1. Racing with multiple threads in order to hit specific code paths. For example, for the [Dirty Cow][dirtycow] privilege escalation bug, an application would open a specific file in `/proc` or use a specific `ptrace` @@ -140,14 +140,14 @@ filesystem attributes) and not underlying host system resources. While the sandbox virtualizes many operations for the application, we limit the sandbox's own interactions with the host to the following high-level operations: - 1. Communicate with a Gofer process via a connected socket. The sandbox may +1. Communicate with a Gofer process via a connected socket. The sandbox may receive new file descriptors from the Gofer process, corresponding to opened files. These files can then be read from and written to by the sandbox. - 1. Make a minimal set of host system calls. The calls do not include the +1. Make a minimal set of host system calls. The calls do not include the creation of new sockets (unless host networking mode is enabled) or opening files. The calls include duplication and closing of file descriptors, synchronization, timers and signal management. - 1. Read and write packets to a virtual ethernet device. This is not required if +1. Read and write packets to a virtual ethernet device. This is not required if host networking is enabled (or networking is disabled). ### System ABI, Side Channels and Other Vectors @@ -173,17 +173,17 @@ less likely to exploit or override these controls through other means. For gVisor development, there are several engineering principles that are employed in order to ensure that the system meets its design goals. - 1. No system call is passed through directly to the host. Every supported call +1. No system call is passed through directly to the host. Every supported call has an independent implementation in the Sentry, that is unlikely to suffer from identical vulnerabilities that may appear in the host. This has the consequence that all kernel features used by applications require an implementation within the Sentry. - 1. Only common, universal functionality is implemented. Some filesystems, +1. Only common, universal functionality is implemented. Some filesystems, network devices or modules may expose specialized functionality to user space applications via mechanisms such as extended attributes, raw sockets or ioctls. Since the Sentry is responsible for implementing the full system call surface, we do not implement or pass through these specialized APIs. - 1. The host surface exposed to the Sentry is minimized. While the system call +1. The host surface exposed to the Sentry is minimized. While the system call surface is not trivial, it is explicitly enumerated and controlled. The Sentry is not permitted to open new files, create new sockets or do many other interesting things on the host. @@ -191,11 +191,11 @@ employed in order to ensure that the system meets its design goals. Additionally, we have practical restrictions that are imposed on the project to minimize the risk of Sentry exploitability. For example: - 1. Unsafe code is carefully controlled. All unsafe code is isolated in files +1. Unsafe code is carefully controlled. All unsafe code is isolated in files that end with "unsafe.go", in order to facilitate validation and auditing. No file without the unsafe suffix may import the unsafe package. - 1. No CGo is allowed. The Sentry must be a pure Go binary. - 1. External imports are not generally allowed within the core packages. Only +1. No CGo is allowed. The Sentry must be a pure Go binary. +1. External imports are not generally allowed within the core packages. Only limited external imports are used within the setup code. The code available inside the Sentry is carefully controlled, to ensure that the above rules are effective. diff --git a/content/docs/community/_index.md b/content/docs/community/_index.md index ed02c8bdc..09e8f5573 100644 --- a/content/docs/community/_index.md +++ b/content/docs/community/_index.md @@ -9,8 +9,8 @@ repositories have their own guidelines and processes for contributing. See the The project maintains two mailing lists: - * [gvisor-users][gvisor-users] for accouncements and general discussion. - * [gvisor-dev][gvisor-dev] for development and contribution. +* [gvisor-users][gvisor-users] for accouncements and general discussion. +* [gvisor-dev][gvisor-dev] for development and contribution. We also have a [chat room hosted on Gitter][gitter-chat]. diff --git a/content/docs/tutorials/docker.md b/content/docs/tutorials/docker.md index 8391515c3..d39b514c6 100644 --- a/content/docs/tutorials/docker.md +++ b/content/docs/tutorials/docker.md @@ -59,7 +59,7 @@ docker run --runtime=runsc --name wordpress -d \ ``` Now, you can access the WordPress website pointing your favorite browser to -http://localhost:8080. +. Congratulations! You have just deployed a WordPress site using Docker. diff --git a/content/docs/tutorials/kubernetes.md b/content/docs/tutorials/kubernetes.md index 03acac756..5a931bae3 100644 --- a/content/docs/tutorials/kubernetes.md +++ b/content/docs/tutorials/kubernetes.md @@ -11,9 +11,9 @@ This page shows you how to deploy a sample [WordPress][wordpress] site using Take the following steps to enable the Kubernetes Engine API: -1. Visit the [Kubernetes Engine page][project-selector] in the Google Cloud - Platform Console. -1. Create or select a project. +1. Visit the [Kubernetes Engine page][project-selector] in the Google Cloud + Platform Console. +1. Create or select a project. ### Creating a node pool with gVisor enabled @@ -235,4 +235,4 @@ a look at the [documentation][gke-sandbox-docs]. [gke-sandbox-docs]: https://cloud.google.com/kubernetes-engine/docs/how-to/sandbox-pods [gke-sandbox]: https://cloud.google.com/kubernetes-engine/sandbox/ [project-selector]: https://console.cloud.google.com/projectselector/kubernetes -[wordpress]: https://wordpress.com/ \ No newline at end of file +[wordpress]: https://wordpress.com/ diff --git a/content/docs/user_guide/FAQ.md b/content/docs/user_guide/FAQ.md index 2cee17477..05455a70f 100644 --- a/content/docs/user_guide/FAQ.md +++ b/content/docs/user_guide/FAQ.md @@ -89,12 +89,12 @@ order to communicate to the DNS server. runsc network is isolated from the host and cannot access the DNS server on the host network without breaking the sandbox isolation. There are a few different workarounds you can try: -* Use default bridge network with `--link` to connect containers. Default - bridge doesn't use embedded DNS. -* Use [`--network=host`][host-net] option in runsc, however beware that it will - use the host network stack and is less secure. -* Use IPs instead of container names. -* Use [Kubernetes][k8s]. Container name lookup works fine in Kubernetes. +* Use default bridge network with `--link` to connect containers. Default + bridge doesn't use embedded DNS. +* Use [`--network=host`][host-net] option in runsc, however beware that it will + use the host network stack and is less secure. +* Use IPs instead of container names. +* Use [Kubernetes][k8s]. Container name lookup works fine in Kubernetes. [security-model]: /docs/architecture_guide/security/ [old-linux]: /docs/user_guide/networking/#gso diff --git a/content/docs/user_guide/checkpoint_restore.md b/content/docs/user_guide/checkpoint_restore.md index bbc08a5f2..f13c5199e 100644 --- a/content/docs/user_guide/checkpoint_restore.md +++ b/content/docs/user_guide/checkpoint_restore.md @@ -20,7 +20,7 @@ file will be called `checkpoint.img` and necessary directories will be created if they do not yet exist. > Note: Two checkpoints cannot be saved to the same directory; every image-path -provided must be unique. +> provided must be unique. ```bash runsc checkpoint --image-path= @@ -31,11 +31,11 @@ continue to run after the checkpoint has been made. (By default, containers stop their processes after committing a checkpoint.) > Note: All top-level runsc flags needed when calling run must be provided to -checkpoint if --leave-running is used. +> checkpoint if --leave-running is used. > Note: --leave-running functions by causing an immediate restore so the -container, although will maintain its given container id, may have a different -process id. +> container, although will maintain its given container id, may have a different +> process id. ```bash runsc checkpoint --image-path= --leave-running @@ -83,19 +83,19 @@ docker start --checkpoint --checkpoint-dir= ### Issues Preventing Compatibility with Docker -- **[Moby #37360][leave-running]:** Docker version 18.03.0-ce and earlier hangs - when checkpointing and does not create the checkpoint. To successfully use - this feature, install a custom version of docker-ce from the moby repository. - This issue is caused by an improper implementation of the `--leave-running` - flag. This issue is fixed in newer releases. -- **Docker does not support restoration into new containers:** Docker currently - expects the container which created the checkpoint to be the same container - used to restore which is not possible in runsc. When Docker supports container - migration and therefore restoration into new containers, this will be the - flow. -- **[Moby #37344][checkpoint-dir]:** Docker does not currently support the - `--checkpoint-dir` flag but this will be required when restoring from a - checkpoint made in another container. +* **[Moby #37360][leave-running]:** Docker version 18.03.0-ce and earlier hangs + when checkpointing and does not create the checkpoint. To successfully use + this feature, install a custom version of docker-ce from the moby repository. + This issue is caused by an improper implementation of the `--leave-running` + flag. This issue is fixed in newer releases. +* **Docker does not support restoration into new containers:** Docker currently + expects the container which created the checkpoint to be the same container + used to restore which is not possible in runsc. When Docker supports container + migration and therefore restoration into new containers, this will be the + flow. +* **[Moby #37344][checkpoint-dir]:** Docker does not currently support the + `--checkpoint-dir` flag but this will be required when restoring from a + checkpoint made in another container. [leave-running]: https://github.com/moby/moby/pull/37360 [checkpoint-dir]: https://github.com/moby/moby/issues/37344 diff --git a/content/docs/user_guide/compatibility/_index.md b/content/docs/user_guide/compatibility/_index.md index 4cd1b31b0..e11e64339 100644 --- a/content/docs/user_guide/compatibility/_index.md +++ b/content/docs/user_guide/compatibility/_index.md @@ -40,10 +40,10 @@ The following applications/images have been tested: Most common utilities work. Note that: -* Some tools, such as `tcpdump` and old versions of `ping`, require explicitly - enabling raw sockets via the unsafe `--net-raw` runsc flag. -* Different Docker images can behave differently. For example, Alpine Linux and - Ubuntu have different `ip` binaries. +* Some tools, such as `tcpdump` and old versions of `ping`, require explicitly + enabling raw sockets via the unsafe `--net-raw` runsc flag. +* Different Docker images can behave differently. For example, Alpine Linux and + Ubuntu have different `ip` binaries. Specific tools include: diff --git a/content/docs/user_guide/debugging.md b/content/docs/user_guide/debugging.md index 4d26d557c..c19269934 100644 --- a/content/docs/user_guide/debugging.md +++ b/content/docs/user_guide/debugging.md @@ -106,9 +106,9 @@ Then restart docker to refresh the runtime options. While the container is runni execute `runsc debug` to collect profile information and save to a file. Here are the options available: - * **--profile-heap:** Generates heap profile to the speficied file. - * **--profile-cpu:** Enables CPU profiler, waits for `--profile-delay` seconds - and generates CPU profile to the speficied file. +* **--profile-heap:** Generates heap profile to the speficied file. +* **--profile-cpu:** Enables CPU profiler, waits for `--profile-delay` seconds + and generates CPU profile to the speficied file. For example: @@ -120,7 +120,7 @@ sudo runsc --root /var/run/docker/runtime-runsc-prof/moby debug --profile-heap=/ sudo runsc --root /var/run/docker/runtime-runsc-prof/moby debug --profile-cpu=/tmp/cpu.prof --profile-delay=30 63254c6ab3a6989623fa1fb53616951eed31ac605a2637bb9ddba5d8d404b35b ``` -The resulting files can be opened using `go tool pprof` or [pprof]. The examples +The resulting files can be opened using `go tool pprof` or [pprof][pprof]. The examples below create image file (`.svg`) with the heap profile and writes the top functions using CPU to the console: diff --git a/content/docs/user_guide/install.md b/content/docs/user_guide/install.md index e18af233b..c966c7bd5 100644 --- a/content/docs/user_guide/install.md +++ b/content/docs/user_guide/install.md @@ -87,10 +87,10 @@ curl -fsSL https://gvisor.dev/archive.key | sudo apt-key add - Based on the release type, you will need to substitute `${DIST}` below, using one of: - * `nightly`: For all nightly releases. - * `latest`: For the latest release. - * `${yyyymmdd}`: For specific releases. - * `${yyyymmdd}.${rc}`: For a specific point release. +* `nightly`: For all nightly releases. +* `latest`: For the latest release. +* `${yyyymmdd}`: For specific releases. +* `${yyyymmdd}.${rc}`: For a specific point release. The repository for the release you wish to install should be added: @@ -153,11 +153,6 @@ runsc install ``` [latest-nightly]: https://storage.googleapis.com/gvisor/releases/nightly/latest/runsc - [latest-hash]: https://storage.googleapis.com/gvisor/releases/nightly/latest/runsc.sha512 - -[oci]: https://www.opencontainers.org - [old-linux]: /docs/user_guide/networking/#gso - [releases]: https://github.com/google/gvisor/releases diff --git a/content/docs/user_guide/platforms.md b/content/docs/user_guide/platforms.md index e15072068..72e640cc8 100644 --- a/content/docs/user_guide/platforms.md +++ b/content/docs/user_guide/platforms.md @@ -58,10 +58,10 @@ If you are using a virtual machine you will need to make sure that nested virtualization is configured. Here are links to documents on how to set up nested virtualization in several popular environments: - * Google Cloud: [Enabling Nested Virtualization for VM Instances][nested-gcp] - * Microsoft Azure: [How to enable nested virtualization in an Azure VM][nested-azure] - * VirtualBox: [Nested Virtualization][nested-virtualbox] - * KVM: [Nested Guests][nested-kvm] +* Google Cloud: [Enabling Nested Virtualization for VM Instances][nested-gcp] +* Microsoft Azure: [How to enable nested virtualization in an Azure VM][nested-azure] +* VirtualBox: [Nested Virtualization][nested-virtualbox] +* KVM: [Nested Guests][nested-kvm] ### Configuring Docker diff --git a/content/docs/user_guide/quick_start/_index.md b/content/docs/user_guide/quick_start/_index.md index 770fd8893..bb35e748f 100644 --- a/content/docs/user_guide/quick_start/_index.md +++ b/content/docs/user_guide/quick_start/_index.md @@ -7,6 +7,6 @@ gVisor can be used with Docker, Kubernetes, or directly using `runsc` with crafted OCI spec for your container. Use the links below to see detailed instructions for each of them: - * [Docker](./docker/): The quickest and easiest way to get started. - * [Kubernetes](./kubernetes/): Isolate Pods in your K8s cluster with gVisor. - * [OCI](./oci/): Expert mode. Customize gVisor for your environment. +* [Docker](./docker/): The quickest and easiest way to get started. +* [Kubernetes](./kubernetes/): Isolate Pods in your K8s cluster with gVisor. +* [OCI](./oci/): Expert mode. Customize gVisor for your environment. diff --git a/content/docs/user_guide/quick_start/kubernetes.md b/content/docs/user_guide/quick_start/kubernetes.md index b3b5e0a55..e21abbc70 100644 --- a/content/docs/user_guide/quick_start/kubernetes.md +++ b/content/docs/user_guide/quick_start/kubernetes.md @@ -36,4 +36,4 @@ WordPress site. You can view the full documentation [here][gke-sandbox-docs]. [gke-sandbox-docs]: https://cloud.google.com/kubernetes-engine/docs/how-to/sandbox-pods [gvisor-containerd-shim]: https://github.com/google/gvisor-containerd-shim [runtimeclass]: https://kubernetes.io/docs/concepts/containers/runtime-class/ -[wordpress-quick]: /docs/tutorials/kubernetes/ \ No newline at end of file +[wordpress-quick]: /docs/tutorials/kubernetes/ diff --git a/package-lock.json b/package-lock.json index 0bcf137bd..538ab13fe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,11 @@ "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", "dev": true }, + "@types/unist": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz", + "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==" + }, "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", @@ -131,6 +136,12 @@ "postcss-value-parser": "^3.3.1" } }, + "bail": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.4.tgz", + "integrity": "sha512-S8vuDB4w6YpRhICUDET3guPlQpaJl7od94tpZ0Fvnyp+MKW/HyDTcRDck+29C9g+d/qQHnddRH3+94kZdrW0Ww==", + "dev": true + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -248,6 +259,12 @@ "node-releases": "^1.1.3" } }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, "cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", @@ -283,6 +300,12 @@ "integrity": "sha512-4bghJFItvzz8m0T3lLZbacmEY9X1Z2AtIzTr7s7byqZIOumASfr4ynDx7rtm0J85nDmx8vsgR6vnaSoeU8Oh0A==", "dev": true }, + "ccount": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.0.4.tgz", + "integrity": "sha512-fpZ81yYfzentuieinmGnphk0pLkOTMm6MZdVqwd77ROvhko6iujLNGrHH5E7utq3ygWklwfmwuG+A7P+NpqT6w==", + "dev": true + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -305,6 +328,30 @@ } } }, + "character-entities": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.3.tgz", + "integrity": "sha512-yB4oYSAa9yLcGyTbB4ItFwHw43QHdH129IJ5R+WvxOkWlyFnR5FAaBNnUq4mcxsTVZGh28bHoeTHMKXH1wZf3w==", + "dev": true + }, + "character-entities-html4": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.3.tgz", + "integrity": "sha512-SwnyZ7jQBCRHELk9zf2CN5AnGEc2nA+uKMZLHvcqhpPprjkYhiLn0DywMHgN5ttFZuITMATbh68M6VIVKwJbcg==", + "dev": true + }, + "character-entities-legacy": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.3.tgz", + "integrity": "sha512-YAxUpPoPwxYFsslbdKkhrGnXAtXoHNgYjlBM3WMXkWGTl5RsY3QmOyhwAgL8Nxm9l5LBThXGawxKPn68y6/fww==", + "dev": true + }, + "character-reference-invalid": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.3.tgz", + "integrity": "sha512-VOq6PRzQBam/8Jm6XBGk2fNEnHXAdGd6go0rtd4weAGECBamHDwwCQSOT12TACIYUZegUXnV6xBXqUssijtxIg==", + "dev": true + }, "chokidar": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", @@ -360,12 +407,22 @@ "wrap-ansi": "^2.0.0" } }, + "co": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/co/-/co-3.1.0.tgz", + "integrity": "sha1-TqVOpaCJOBUxheFSEMaNkJK8G3g=" + }, "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, + "collapse-white-space": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.5.tgz", + "integrity": "sha512-703bOOmytCYAX9cXYqoikYIx6twmFCXsnzRQheBcTG3nzKYBR4P/+wkYeH+Mvj7qUz8zZDtdyzbxfnEi/kYzRQ==" + }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", @@ -403,6 +460,31 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, "copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", @@ -461,6 +543,12 @@ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, "define-property": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", @@ -524,6 +612,12 @@ "integrity": "sha512-/QI4hMpAh48a1Sea6PALGv+kuVne9A2EWGd8HrWHMdYhIzGtbhVVHh6heL5fAzGaDnZuPyrlWJRl8WPm4RyiQQ==", "dev": true }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", @@ -604,6 +698,12 @@ } } }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, "extend-shallow": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", @@ -704,6 +804,24 @@ "micromatch": "^3.1.10" } }, + "fault": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.3.tgz", + "integrity": "sha512-sfFuP4X0hzrbGKjAUNXYvNqsZ5F6ohx/dZ9I0KQud/aiZNwg263r5L9yGB0clvXHCkzXh5W3t7RSHchggYIFmA==", + "dev": true, + "requires": { + "format": "^0.2.2" + } + }, + "figures": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz", + "integrity": "sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -736,12 +854,24 @@ "locate-path": "^3.0.0" } }, + "fn-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fn-name/-/fn-name-2.0.1.tgz", + "integrity": "sha1-UhTXU3pNBqSjAcDMJi/rhBiAAuc=", + "dev": true + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", "dev": true }, + "format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs=", + "dev": true + }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -788,8 +918,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -810,14 +939,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -832,20 +959,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -962,8 +1086,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -975,7 +1098,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -990,7 +1112,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -998,14 +1119,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -1024,7 +1143,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -1105,8 +1223,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -1118,7 +1235,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -1204,8 +1320,7 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -1241,7 +1356,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -1261,7 +1375,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -1305,14 +1418,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, @@ -1483,12 +1594,23 @@ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, "invert-kv": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", "dev": true }, + "irregular-plurals": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-2.0.0.tgz", + "integrity": "sha512-Y75zBYLkh0lJ9qxeHlMjQ7bSbyiSqNW/UOPWDmzC7cXskL1hekSITh1Oc6JV0XCWWZ9DE8VYSB71xocLk3gmGw==" + }, "is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", @@ -1509,6 +1631,28 @@ } } }, + "is-alphabetical": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.3.tgz", + "integrity": "sha512-eEMa6MKpHFzw38eKm56iNNi6GJ7lf6aLLio7Kr23sJPAECscgRtZvOBYybejWDQ2bM949Y++61PY+udzj5QMLA==", + "dev": true + }, + "is-alphanumeric": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-alphanumeric/-/is-alphanumeric-1.0.0.tgz", + "integrity": "sha1-Spzvcdr0wAHB2B1j0UDPU/1oifQ=", + "dev": true + }, + "is-alphanumerical": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.3.tgz", + "integrity": "sha512-A1IGAPO5AW9vSh7omxIlOGwIqEvpW/TA+DksVOPM5ODuxKlZS09+TEM1E3275lJqO2oJ38vDpeAL3DCIiHE6eA==", + "dev": true, + "requires": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + } + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -1550,6 +1694,12 @@ } } }, + "is-decimal": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.3.tgz", + "integrity": "sha512-bvLSwoDg2q6Gf+E2LEPiklHZxxiSi3XAh4Mav65mKqTfCO1HM3uBs24TjEH8iJX3bbDdLXKJXBTmGzuTUuAEjQ==", + "dev": true + }, "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", @@ -1575,6 +1725,12 @@ "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", "dev": true }, + "is-empty": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-empty/-/is-empty-1.2.0.tgz", + "integrity": "sha1-3pu1snhzigWgsJpX4ftNSjQan2s=", + "dev": true + }, "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", @@ -1602,6 +1758,18 @@ "is-extglob": "^2.1.1" } }, + "is-hexadecimal": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.3.tgz", + "integrity": "sha512-zxQ9//Q3D/34poZf8fiy3m3XVpbQc7ren15iKqrTtLPwkPD/t3Scy9Imp63FujULGxuK0ZlCwoo5xNpktFgbOA==", + "dev": true + }, + "is-hidden": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-hidden/-/is-hidden-1.1.2.tgz", + "integrity": "sha512-kytBeNVW2QTIqZdJBDKIjP+EkUTzDT07rsc111w/gxqR6wK3ODkOswcpxgED6HU6t7fEhOxqojVZ2a2kU9rj+A==", + "dev": true + }, "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", @@ -1622,6 +1790,18 @@ } } }, + "is-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", + "dev": true + }, + "is-plain-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.0.0.tgz", + "integrity": "sha512-EYisGhpgSCwspmIuRHGjROWTon2Xp8Z7U03Wubk/bTL5TTRC5R1rGVgyjzBrk9+ULdH6cRD06KRcw/xfqhVYKQ==", + "dev": true + }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -1637,12 +1817,24 @@ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, + "is-whitespace-character": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.3.tgz", + "integrity": "sha512-SNPgMLz9JzPccD3nPctcj8sZlX9DAMJSKH8bP7Z6bohCwuNgX8xbWr1eTAYXX9Vpi/aSn8Y1akL9WgM3t43YNQ==", + "dev": true + }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true }, + "is-word-character": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.3.tgz", + "integrity": "sha512-0wfcrFgOOOBdgRNT9H33xe6Zi6yhX/uoc4U8NBZGeQQB0ctU1dnlNTyL9JM2646bHDTpsDm1Brb3VPoCIMrd/A==", + "dev": true + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -1677,6 +1869,15 @@ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, + "json5": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", + "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, "jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", @@ -1701,6 +1902,24 @@ "invert-kv": "^2.0.0" } }, + "load-plugin": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/load-plugin/-/load-plugin-2.3.1.tgz", + "integrity": "sha512-dYB1lbwqHgPTrruy9glukCu8Ya9vzj6TMfouCtj2H/GuJ+8syioisgKTBPxnCi6m8K8jINKfTOxOHngFkUYqHw==", + "dev": true, + "requires": { + "npm-prefix": "^1.2.0", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", @@ -1732,6 +1951,12 @@ "chalk": "^2.0.1" } }, + "longest-streak": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.3.tgz", + "integrity": "sha512-9lz5IVdpwsKLMzQi0MQ+oD9EA0mIGcWYP7jXMTZVXP8D42PwuAk+M/HBFYQoxt1G5OR8m7aSIgb1UymfWGBWEw==", + "dev": true + }, "map-age-cleaner": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", @@ -1756,6 +1981,48 @@ "object-visit": "^1.0.0" } }, + "markdown-escapes": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.3.tgz", + "integrity": "sha512-XUi5HJhhV5R74k8/0H2oCbCiYf/u4cO/rX8tnGkRvrqhsr5BRNU6Mg0yt/8UIx1iIS8220BNJsDb7XnILhLepw==", + "dev": true + }, + "markdown-extensions": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-1.1.1.tgz", + "integrity": "sha512-WWC0ZuMzCyDHYCasEGs4IPvLyTGftYwh6wIEOULOF0HXcqZlhwRzrK0w2VUlxWA98xnvb/jszw4ZSkJ6ADpM6Q==", + "dev": true + }, + "markdown-table": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz", + "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==", + "dev": true + }, + "mdast-comment-marker": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/mdast-comment-marker/-/mdast-comment-marker-1.1.1.tgz", + "integrity": "sha512-TWZDaUtPLwKX1pzDIY48MkSUQRDwX/HqbTB4m3iYdL/zosi/Z6Xqfdv0C0hNVKvzrPjZENrpWDt4p4odeVO0Iw==" + }, + "mdast-util-compact": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-compact/-/mdast-util-compact-1.0.3.tgz", + "integrity": "sha512-nRiU5GpNy62rZppDKbLwhhtw5DXoFMqw9UNZFmlPsNaQCZ//WLjGKUwWMdJrUH+Se7UvtO2gXtAMe0g/N+eI5w==", + "dev": true, + "requires": { + "unist-util-visit": "^1.1.0" + } + }, + "mdast-util-heading-style": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/mdast-util-heading-style/-/mdast-util-heading-style-1.0.5.tgz", + "integrity": "sha512-8zQkb3IUwiwOdUw6jIhnwM6DPyib+mgzQuHAe7j2Hy1rIarU4VUxe472bp9oktqULW3xqZE+Kz6OD4Gi7IA3vw==" + }, + "mdast-util-to-string": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-1.0.6.tgz", + "integrity": "sha512-868pp48gUPmZIhfKrLbaDneuzGiw3OTDjHc5M1kAepR2CWBJ+HpEsm252K4aXdiP5coVZaJPOqGtVU6Po8xnXg==" + }, "mem": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/mem/-/mem-4.0.0.tgz", @@ -1809,6 +2076,12 @@ "brace-expansion": "^1.1.7" } }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, "mixin-deep": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", @@ -1892,6 +2165,17 @@ "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", "dev": true }, + "npm-prefix": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/npm-prefix/-/npm-prefix-1.2.0.tgz", + "integrity": "sha1-5hlFX3B0ulTMZtbQ033Z8b5ry8A=", + "dev": true, + "requires": { + "rc": "^1.1.0", + "shellsubstitute": "^1.1.0", + "untildify": "^2.1.0" + } + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -1971,6 +2255,12 @@ "wrappy": "1" } }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, "os-locale": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", @@ -2024,6 +2314,20 @@ "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", "dev": true }, + "parse-entities": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-1.2.2.tgz", + "integrity": "sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg==", + "dev": true, + "requires": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + } + }, "parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -2073,12 +2377,26 @@ "pify": "^3.0.0" } }, + "picomatch": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.0.7.tgz", + "integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==", + "dev": true + }, "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true }, + "plur": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/plur/-/plur-3.1.1.tgz", + "integrity": "sha512-t1Ax8KUvV3FFII8ltczPn2tJdjqbd1sIzu6t4JL7nQ3EyeL/lTrj5PWKb06ic5/6XYDr65rQ4uzQEGN70/6X5w==", + "requires": { + "irregular-plurals": "^2.0.0" + } + }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -2166,6 +2484,18 @@ "once": "^1.3.1" } }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, "read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -2219,6 +2549,281 @@ "safe-regex": "^1.1.0" } }, + "remark": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/remark/-/remark-11.0.1.tgz", + "integrity": "sha512-Fl2AvN+yU6sOBAjUz3xNC5iEvLkXV8PZicLOOLifjU8uKGusNvhHfGRCfETsqyvRHZ24JXqEyDY4hRLhoUd30A==", + "dev": true, + "requires": { + "remark-parse": "^7.0.0", + "remark-stringify": "^7.0.0", + "unified": "^8.2.0" + } + }, + "remark-cli": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/remark-cli/-/remark-cli-7.0.0.tgz", + "integrity": "sha512-gYomWviFnZsiRimG+Jdb4LQ9c8uSOcGmPTmzlvxImt0gvzabqlp1kaqndxTx4kYLsWGqwhQRO+M9iyqHDkoDlA==", + "dev": true, + "requires": { + "markdown-extensions": "^1.1.0", + "remark": "^11.0.0", + "unified-args": "^7.0.0" + } + }, + "remark-lint": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/remark-lint/-/remark-lint-6.0.5.tgz", + "integrity": "sha512-o1I3ddm+KNsTxk60wWGI+p2yU1jB1gcm8jo2Sy6VhJ4ab2TrQIp1oQbp5xeLoFXYSh/NAqCpKjHkCM/BYpkFdQ==", + "requires": { + "remark-message-control": "^4.0.0" + } + }, + "remark-lint-final-newline": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/remark-lint-final-newline/-/remark-lint-final-newline-1.0.3.tgz", + "integrity": "sha512-ETAadktv75EwUS3XDhyZUVstXKxfPAEn7SmfN9kZ4+Jb4qo4hHE9gtTOzhE6HxLUxxl9BBhpC5mMO3JcL8UZ5A==", + "requires": { + "unified-lint-rule": "^1.0.0" + } + }, + "remark-lint-hard-break-spaces": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/remark-lint-hard-break-spaces/-/remark-lint-hard-break-spaces-1.0.4.tgz", + "integrity": "sha512-YM82UpgliZCZhGNmFxEe7ArfhqR5CplFf2bc0k0+8w3rKWKx7EJcGMar2NK410tIi40gGeWtH/pIEypPJFCCiA==", + "requires": { + "unified-lint-rule": "^1.0.0", + "unist-util-generated": "^1.1.0", + "unist-util-position": "^3.0.0", + "unist-util-visit": "^1.1.1" + } + }, + "remark-lint-list-item-bullet-indent": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/remark-lint-list-item-bullet-indent/-/remark-lint-list-item-bullet-indent-1.0.3.tgz", + "integrity": "sha512-iVxQbrgzLpMHG3C6o6wRta/+Bc96etOiBYJnh2zm/aWz6DJ7cGLDykngblP/C4he7LYSeWOD/8Y57HbXZwM2Og==", + "requires": { + "plur": "^3.0.0", + "unified-lint-rule": "^1.0.0", + "unist-util-generated": "^1.1.0", + "unist-util-position": "^3.0.0", + "unist-util-visit": "^1.1.1" + } + }, + "remark-lint-list-item-indent": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/remark-lint-list-item-indent/-/remark-lint-list-item-indent-1.0.4.tgz", + "integrity": "sha512-Sv0gVH6qP1/nFpbJuyyguB9sAD2o42StD2WbEZeUcEexXwRO4u/YaX0Pm5pMtCiEHyN+qyL6ShKBQMtgol9BeA==", + "requires": { + "plur": "^3.0.0", + "unified-lint-rule": "^1.0.0", + "unist-util-generated": "^1.1.0", + "unist-util-position": "^3.0.0", + "unist-util-visit": "^1.1.1" + } + }, + "remark-lint-no-auto-link-without-protocol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/remark-lint-no-auto-link-without-protocol/-/remark-lint-no-auto-link-without-protocol-1.0.3.tgz", + "integrity": "sha512-k+hg2mXnO4Q9WV+UShPLen5oThvFxcRVWkx2hviVd/nu3eiszBKH3o38csBwjeJoMG3l2ZhdUW8dlOBhq8670Q==", + "requires": { + "mdast-util-to-string": "^1.0.2", + "unified-lint-rule": "^1.0.0", + "unist-util-generated": "^1.1.0", + "unist-util-position": "^3.0.0", + "unist-util-visit": "^1.1.1" + } + }, + "remark-lint-no-blockquote-without-marker": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/remark-lint-no-blockquote-without-marker/-/remark-lint-no-blockquote-without-marker-2.0.3.tgz", + "integrity": "sha512-faDzKrA6aKidsRXG6gcIlCO8TexLxIxe+n9B3mdnl8mhZGgE0FfWTkIWVMj0IYps/xVsVMf45KxhXgc1wU9kwg==", + "requires": { + "unified-lint-rule": "^1.0.0", + "unist-util-generated": "^1.1.0", + "unist-util-position": "^3.0.0", + "unist-util-visit": "^1.1.1", + "vfile-location": "^2.0.1" + } + }, + "remark-lint-no-duplicate-definitions": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/remark-lint-no-duplicate-definitions/-/remark-lint-no-duplicate-definitions-1.0.5.tgz", + "integrity": "sha512-zKXmfNUODXhJsGQdqfguMG9Nl9v1sLaDsQgMjUtmOSoQRnNud9ThQAZl62eX5jBn5HKcpOifG80tgkyBvU5eEw==", + "requires": { + "unified-lint-rule": "^1.0.0", + "unist-util-generated": "^1.1.0", + "unist-util-position": "^3.0.0", + "unist-util-stringify-position": "^2.0.0", + "unist-util-visit": "^1.4.0" + } + }, + "remark-lint-no-heading-content-indent": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/remark-lint-no-heading-content-indent/-/remark-lint-no-heading-content-indent-1.0.3.tgz", + "integrity": "sha512-7xM6X5E/dt8OXOHdejH+sfYb139a3kMr8ZSSkcp90Ab1y+ZQBNaWsR3mYh8FRKkYPTN5eyd+KjhNpLWyqqCbgg==", + "requires": { + "mdast-util-heading-style": "^1.0.2", + "plur": "^3.0.0", + "unified-lint-rule": "^1.0.0", + "unist-util-generated": "^1.1.0", + "unist-util-position": "^3.0.0", + "unist-util-visit": "^1.1.1" + } + }, + "remark-lint-no-inline-padding": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/remark-lint-no-inline-padding/-/remark-lint-no-inline-padding-1.0.4.tgz", + "integrity": "sha512-u5rgbDkcfVv645YxxOwoGBBJbsHEwWm/XqnO8EhfKTxkfKOF4ZItG7Ajhj89EDaeXMkvCcB/avBl4bj50eJH3g==", + "requires": { + "mdast-util-to-string": "^1.0.2", + "unified-lint-rule": "^1.0.0", + "unist-util-generated": "^1.1.0", + "unist-util-visit": "^1.4.0" + } + }, + "remark-lint-no-literal-urls": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/remark-lint-no-literal-urls/-/remark-lint-no-literal-urls-1.0.3.tgz", + "integrity": "sha512-H5quyMzl2kaewK+jYD1FI0G1SIinIsIp4DEyOUwIR+vYUoKwo0B4vvW0cmPpD1dgqqxHYx0B2B0JQQKFVWzGiw==", + "requires": { + "mdast-util-to-string": "^1.0.2", + "unified-lint-rule": "^1.0.0", + "unist-util-generated": "^1.1.0", + "unist-util-position": "^3.0.0", + "unist-util-visit": "^1.1.1" + } + }, + "remark-lint-no-shortcut-reference-image": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/remark-lint-no-shortcut-reference-image/-/remark-lint-no-shortcut-reference-image-1.0.3.tgz", + "integrity": "sha512-CGm27X54kXp/5ehXejDTsZjqzK4uIhLGcrFzN3k/KjdwunQouEY92AARGrLSEuJ1hQx0bJsmnvr/hvQyWAfNJg==", + "requires": { + "unified-lint-rule": "^1.0.0", + "unist-util-generated": "^1.1.0", + "unist-util-visit": "^1.1.1" + } + }, + "remark-lint-no-shortcut-reference-link": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/remark-lint-no-shortcut-reference-link/-/remark-lint-no-shortcut-reference-link-1.0.4.tgz", + "integrity": "sha512-FXdMJYqspZBhPlxYqfVgVluVXjxStg0RHJzqrk8G9wS8fCS62AE3reoaoiCahwoH1tfKcA+poktbKqDAmZo7Jg==", + "requires": { + "unified-lint-rule": "^1.0.0", + "unist-util-generated": "^1.1.0", + "unist-util-visit": "^1.1.1" + } + }, + "remark-lint-no-undefined-references": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/remark-lint-no-undefined-references/-/remark-lint-no-undefined-references-1.1.1.tgz", + "integrity": "sha512-b1eIjWFaCu6m16Ax2uG33o1v+eRYqDTQRUqU6UeQ76JXmDmVtVO75ZuyRpqqE7VTZRW8YLVurXfJPDXfIa5Wng==", + "requires": { + "collapse-white-space": "^1.0.4", + "unified-lint-rule": "^1.0.0", + "unist-util-generated": "^1.1.0", + "unist-util-visit": "^1.4.0" + } + }, + "remark-lint-no-unused-definitions": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/remark-lint-no-unused-definitions/-/remark-lint-no-unused-definitions-1.0.5.tgz", + "integrity": "sha512-Bo22e0RNzc1QMW317KTuStGFDG7uTDUQhm/TrW6Qzud0WXnNnqUyvts+e7wTYoj8VnwhhjyjyoA9lKA3uXMdAQ==", + "requires": { + "unified-lint-rule": "^1.0.0", + "unist-util-generated": "^1.1.0", + "unist-util-visit": "^1.4.0" + } + }, + "remark-lint-ordered-list-marker-style": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/remark-lint-ordered-list-marker-style/-/remark-lint-ordered-list-marker-style-1.0.3.tgz", + "integrity": "sha512-24TmW1eUa/2JlwprZg9jJ8LKLxNGKnlKiI5YOhN4taUp2yv8daqlV9vR54yfn/ZZQh6EQvbIX0jeVY9NYgQUtw==", + "requires": { + "unified-lint-rule": "^1.0.0", + "unist-util-generated": "^1.1.0", + "unist-util-position": "^3.0.0", + "unist-util-visit": "^1.1.1" + } + }, + "remark-message-control": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/remark-message-control/-/remark-message-control-4.2.0.tgz", + "integrity": "sha512-WXH2t5ljTyhsXlK1zPBLF3iPHbXl58R94phPMreS1xcHWBZJt6Oiu8RtNjy1poZFb3PqKnbYLJeR/CWcZ1bTFw==", + "requires": { + "mdast-comment-marker": "^1.0.0", + "unified-message-control": "^1.0.0", + "xtend": "^4.0.1" + } + }, + "remark-parse": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-7.0.1.tgz", + "integrity": "sha512-WOZLa545jYXtSy+txza6ACudKWByQac4S2DmGk+tAGO/3XnVTOxwyCIxB7nTcLlk8Aayhcuf3cV1WV6U6L7/DQ==", + "dev": true, + "requires": { + "collapse-white-space": "^1.0.2", + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-whitespace-character": "^1.0.0", + "is-word-character": "^1.0.0", + "markdown-escapes": "^1.0.0", + "parse-entities": "^1.1.0", + "repeat-string": "^1.5.4", + "state-toggle": "^1.0.0", + "trim": "0.0.1", + "trim-trailing-lines": "^1.0.0", + "unherit": "^1.0.4", + "unist-util-remove-position": "^1.0.0", + "vfile-location": "^2.0.0", + "xtend": "^4.0.1" + } + }, + "remark-preset-lint-recommended": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/remark-preset-lint-recommended/-/remark-preset-lint-recommended-3.0.3.tgz", + "integrity": "sha512-5sQ34j1Irlsj6Tt4WWRylZ7UU+1jD5es/LfDZBZp/LXDwC4ldGqKpMmCCR6Z00x1jYM1phmS4M+eGqTdah0qkQ==", + "requires": { + "remark-lint": "^6.0.0", + "remark-lint-final-newline": "^1.0.0", + "remark-lint-hard-break-spaces": "^1.0.0", + "remark-lint-list-item-bullet-indent": "^1.0.0", + "remark-lint-list-item-indent": "^1.0.0", + "remark-lint-no-auto-link-without-protocol": "^1.0.0", + "remark-lint-no-blockquote-without-marker": "^2.0.0", + "remark-lint-no-duplicate-definitions": "^1.0.0", + "remark-lint-no-heading-content-indent": "^1.0.0", + "remark-lint-no-inline-padding": "^1.0.0", + "remark-lint-no-literal-urls": "^1.0.0", + "remark-lint-no-shortcut-reference-image": "^1.0.0", + "remark-lint-no-shortcut-reference-link": "^1.0.0", + "remark-lint-no-undefined-references": "^1.0.0", + "remark-lint-no-unused-definitions": "^1.0.0", + "remark-lint-ordered-list-marker-style": "^1.0.0" + } + }, + "remark-stringify": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-7.0.3.tgz", + "integrity": "sha512-+jgmjNjm2kR7y2Ns1BATXRlFr+iQ7sDcpSgytfU77nkw7UCd5yJNArSxB3MU3Uul7HuyYNTCjetoGfy8xLia1A==", + "dev": true, + "requires": { + "ccount": "^1.0.0", + "is-alphanumeric": "^1.0.0", + "is-decimal": "^1.0.0", + "is-whitespace-character": "^1.0.0", + "longest-streak": "^2.0.1", + "markdown-escapes": "^1.0.0", + "markdown-table": "^1.1.0", + "mdast-util-compact": "^1.0.0", + "parse-entities": "^1.0.2", + "repeat-string": "^1.5.4", + "state-toggle": "^1.0.0", + "stringify-entities": "^2.0.0", + "unherit": "^1.0.4", + "xtend": "^4.0.1" + } + }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -2237,6 +2842,12 @@ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", "dev": true }, + "replace-ext": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", + "dev": true + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -2338,6 +2949,12 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, + "shellsubstitute": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shellsubstitute/-/shellsubstitute-1.2.0.tgz", + "integrity": "sha1-5PcCpQxRiw9v6YRRiQ1wWvKba3A=", + "dev": true + }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", @@ -2350,6 +2967,11 @@ "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", "dev": true }, + "sliced": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", + "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -2503,6 +3125,12 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "state-toggle": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.2.tgz", + "integrity": "sha512-8LpelPGR0qQM4PnfLiplOQNJcIN1/r2Gy0xKB2zKnIW2YzPMt2sR4I/+gtPjhN7Svh9kw+zqEg2SFwpBO9iNiw==", + "dev": true + }, "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", @@ -2543,6 +3171,19 @@ "safe-buffer": "~5.1.0" } }, + "stringify-entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-2.0.0.tgz", + "integrity": "sha512-fqqhZzXyAM6pGD9lky/GOPq6V4X0SeTAFBl0iXb/BzOegl40gpf/bV3QQP7zULNYvjr6+Dx8SCaDULjVoOru0A==", + "dev": true, + "requires": { + "character-entities-html4": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.2", + "is-hexadecimal": "^1.0.0" + } + }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", @@ -2558,6 +3199,12 @@ "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, "supports-color": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", @@ -2567,6 +3214,12 @@ "has-flag": "^3.0.0" } }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", @@ -2609,6 +3262,271 @@ "repeat-string": "^1.6.1" } }, + "to-vfile": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/to-vfile/-/to-vfile-6.0.0.tgz", + "integrity": "sha512-i9fwXXSsHLu7mzgixc1WjgnqSe6pGpjnzCYoFmrASvEueLfyKf09QAe+XQYu8OAJ62aFqHpe2EKXojeRVvEzqA==", + "dev": true, + "requires": { + "is-buffer": "^2.0.0", + "vfile": "^4.0.0" + }, + "dependencies": { + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", + "dev": true + } + } + }, + "trim": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", + "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=" + }, + "trim-trailing-lines": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.2.tgz", + "integrity": "sha512-MUjYItdrqqj2zpcHFTkMa9WAv4JHTI6gnRQGPFLrt5L9a6tRMiDnIqYl8JBvu2d2Tc3lWJKQwlGCp0K8AvCM+Q==", + "dev": true + }, + "trough": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.4.tgz", + "integrity": "sha512-tdzBRDGWcI1OpPVmChbdSKhvSVurznZ8X36AYURAcl+0o2ldlCY2XPzyXNNxwJwwyIU+rIglTCG4kxtNKBQH7Q==", + "dev": true + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "unherit": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.2.tgz", + "integrity": "sha512-W3tMnpaMG7ZY6xe/moK04U9fBhi6wEiCYHUW5Mop/wQHf12+79EQGwxYejNdhEz2mkqkBlGwm7pxmgBKMVUj0w==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "xtend": "^4.0.1" + } + }, + "unified": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/unified/-/unified-8.4.1.tgz", + "integrity": "sha512-YPj/uIIZSO7mMIZQj/5Z3hDl4lshWYRQGs5TgUCjHTVdklUWH+O94mK5Cy77SEcmEUwGhnUcudMuH/zIwporqw==", + "dev": true, + "requires": { + "bail": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^2.0.0", + "trough": "^1.0.0", + "vfile": "^4.0.0" + } + }, + "unified-args": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/unified-args/-/unified-args-7.1.0.tgz", + "integrity": "sha512-soi9Rn7l5c1g0RfElSCHMwaxeiclSI0EsS3uZmMPUOfwMeeeZjLpNmHAowV9iSlQh59iiZhSMyQu9lB8WnIz5g==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "chalk": "^2.0.0", + "chokidar": "^3.0.0", + "fault": "^1.0.2", + "json5": "^2.0.0", + "minimist": "^1.2.0", + "text-table": "^0.2.0", + "unified-engine": "^7.0.0" + }, + "dependencies": { + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "dev": true + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "chokidar": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.2.2.tgz", + "integrity": "sha512-bw3pm7kZ2Wa6+jQWYP/c7bAZy3i4GwiIiMO2EeRjrE48l8vBqC/WvFhSF0xyM8fQiPEGvwMY/5bqDG7sSEOuhg==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "fsevents": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.1.tgz", + "integrity": "sha512-4FRPXWETxtigtJW/gxzEDsX1LVbPAM93VleB83kZB+ellqbHMkyt2aJfuzNLRvFPnGi6bcE5SvfxgbXPeKteJw==", + "dev": true, + "optional": true + }, + "glob-parent": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.4" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + } + } + }, + "unified-engine": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/unified-engine/-/unified-engine-7.0.0.tgz", + "integrity": "sha512-zH/MvcISpWg3JZtCoY/GYBw1WnVHkhnPoMBWpmuvAifCPSS9mzT9EbtimesJp6t2nnr/ojI0mg3TmkO1CjIwVA==", + "dev": true, + "requires": { + "concat-stream": "^2.0.0", + "debug": "^4.0.0", + "fault": "^1.0.0", + "figures": "^3.0.0", + "fn-name": "^2.0.1", + "glob": "^7.0.3", + "ignore": "^5.0.0", + "is-empty": "^1.0.0", + "is-hidden": "^1.0.1", + "is-object": "^1.0.1", + "js-yaml": "^3.6.1", + "load-plugin": "^2.0.0", + "parse-json": "^4.0.0", + "to-vfile": "^6.0.0", + "trough": "^1.0.0", + "unist-util-inspect": "^4.1.2", + "vfile-reporter": "^6.0.0", + "vfile-statistics": "^1.1.0", + "x-is-string": "^0.1.0", + "xtend": "^4.0.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ignore": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", + "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "unified-lint-rule": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unified-lint-rule/-/unified-lint-rule-1.0.4.tgz", + "integrity": "sha512-q9wY6S+d38xRAuWQVOMjBQYi7zGyKkY23ciNafB8JFVmDroyKjtytXHCg94JnhBCXrNqpfojo3+8D+gmF4zxJQ==", + "requires": { + "wrapped": "^1.0.1" + } + }, + "unified-message-control": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unified-message-control/-/unified-message-control-1.0.4.tgz", + "integrity": "sha512-e1dEtN4Z/TvLn/qHm+xeZpzqhJTtfZusFErk336kkZVpqrJYiV9ptxq+SbRPFMlN0OkjDYHmVJ929KYjsMTo3g==", + "requires": { + "trim": "0.0.1", + "unist-util-visit": "^1.0.0", + "vfile-location": "^2.0.0" + } + }, "union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", @@ -2621,6 +3539,63 @@ "set-value": "^2.0.1" } }, + "unist-util-generated": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.4.tgz", + "integrity": "sha512-SA7Sys3h3X4AlVnxHdvN/qYdr4R38HzihoEVY2Q2BZu8NHWDnw5OGcC/tXWjQfd4iG+M6qRFNIRGqJmp2ez4Ww==" + }, + "unist-util-inspect": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/unist-util-inspect/-/unist-util-inspect-4.1.4.tgz", + "integrity": "sha512-7xxyvKiZ1SC9vL5qrMqKub1T31gRHfau4242F69CcaOrXt//5PmRVOmDZ36UAEgiT+tZWzmQmbNZn+mVtnR9HQ==", + "dev": true, + "requires": { + "is-empty": "^1.0.0" + } + }, + "unist-util-is": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz", + "integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==" + }, + "unist-util-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-3.0.3.tgz", + "integrity": "sha512-28EpCBYFvnMeq9y/4w6pbnFmCUfzlsc41NJui5c51hOFjBA1fejcwc+5W4z2+0ECVbScG3dURS3JTVqwenzqZw==" + }, + "unist-util-remove-position": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-1.1.3.tgz", + "integrity": "sha512-CtszTlOjP2sBGYc2zcKA/CvNdTdEs3ozbiJ63IPBxh8iZg42SCCb8m04f8z2+V1aSk5a7BxbZKEdoDjadmBkWA==", + "dev": true, + "requires": { + "unist-util-visit": "^1.1.0" + } + }, + "unist-util-stringify-position": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.1.tgz", + "integrity": "sha512-Zqlf6+FRI39Bah8Q6ZnNGrEHUhwJOkHde2MHVk96lLyftfJJckaPslKgzhVcviXj8KcE9UJM9F+a4JEiBUTYgA==", + "requires": { + "@types/unist": "^2.0.2" + } + }, + "unist-util-visit": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.4.1.tgz", + "integrity": "sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==", + "requires": { + "unist-util-visit-parents": "^2.0.0" + } + }, + "unist-util-visit-parents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz", + "integrity": "sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==", + "requires": { + "unist-util-is": "^3.0.0" + } + }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -2667,6 +3642,15 @@ } } }, + "untildify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-2.1.0.tgz", + "integrity": "sha1-F+soB5h/dpUunASF/DEdBqgmouA=", + "dev": true, + "requires": { + "os-homedir": "^1.0.0" + } + }, "upath": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", @@ -2691,6 +3675,102 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, + "vfile": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.0.1.tgz", + "integrity": "sha512-lRHFCuC4SQBFr7Uq91oJDJxlnftoTLQ7eKIpMdubhYcVMho4781a8MWXLy3qZrZ0/STD1kRiKc0cQOHm4OkPeA==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "replace-ext": "1.0.0", + "unist-util-stringify-position": "^2.0.0", + "vfile-message": "^2.0.0" + }, + "dependencies": { + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", + "dev": true + } + } + }, + "vfile-location": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-2.0.5.tgz", + "integrity": "sha512-Pa1ey0OzYBkLPxPZI3d9E+S4BmvfVwNAAXrrqGbwTVXWaX2p9kM1zZ+n35UtVM06shmWKH4RPRN8KI80qE3wNQ==" + }, + "vfile-message": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.1.tgz", + "integrity": "sha512-KtasSV+uVU7RWhUn4Lw+wW1Zl/nW8JWx7JCPps10Y9JRRIDeDXf8wfBLoOSsJLyo27DqMyAi54C6Jf/d6Kr2Bw==", + "dev": true, + "requires": { + "@types/unist": "^2.0.2", + "unist-util-stringify-position": "^2.0.0" + } + }, + "vfile-reporter": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/vfile-reporter/-/vfile-reporter-6.0.0.tgz", + "integrity": "sha512-8Is0XxFxWJUhPJdOg3CyZTqd3ICCWg6r304PuBl818ZG91h4FMS3Q+lrOPS+cs5/DZK3H0+AkJdH0J8JEwKtDA==", + "dev": true, + "requires": { + "repeat-string": "^1.5.0", + "string-width": "^4.0.0", + "supports-color": "^6.0.0", + "unist-util-stringify-position": "^2.0.0", + "vfile-sort": "^2.1.2", + "vfile-statistics": "^1.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.1.0.tgz", + "integrity": "sha512-NrX+1dVVh+6Y9dnQ19pR0pP4FiEIlUvdTGn8pw6CKTNq5sgib2nIhmUNT5TAmhWmvKr3WcxBcP3E8nWezuipuQ==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^5.2.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "vfile-sort": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/vfile-sort/-/vfile-sort-2.2.1.tgz", + "integrity": "sha512-5dt7xEhC44h0uRQKhbM2JAe0z/naHphIZlMOygtMBM9Nn0pZdaX5fshhwWit9wvsuP8t/wp43nTDRRErO1WK8g==", + "dev": true + }, + "vfile-statistics": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/vfile-statistics/-/vfile-statistics-1.1.3.tgz", + "integrity": "sha512-CstaK/ebTz1W3Qp41Bt9Lj/2DmumFsCwC2sKahDNSPh0mPh7/UyMLCoU8ZBX34CRU0d61B4W41yIFsV0NKMZeA==", + "dev": true + }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -2753,12 +3833,32 @@ } } }, + "wrapped": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wrapped/-/wrapped-1.0.1.tgz", + "integrity": "sha1-x4PZ2Aeyc+mwHoUWgKk4yHyQckI=", + "requires": { + "co": "3.1.0", + "sliced": "^1.0.1" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, + "x-is-string": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/x-is-string/-/x-is-string-0.1.0.tgz", + "integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, "y18n": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", diff --git a/package.json b/package.json index 7e5f58b09..e9e0461b3 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,18 @@ { - "name": "gvisor-website", - "version": "0.0.0", - "devDependencies": { - "autoprefixer": "^9.4.7", - "postcss-cli": "^6.1.1" - } + "name": "gvisor-website", + "version": "0.0.0", + "devDependencies": { + "autoprefixer": "^9.4.7", + "postcss-cli": "^6.1.1", + "remark-cli": "^7.0.0", + "remark-preset-lint-recommended": "^3.0.3" + }, + "scripts": { + "lint-md": "remark ./content -f" + }, + "remarkConfig": { + "plugins": [ + "remark-preset-lint-recommended" + ] + } } From c73410c0bda98fa617d82cf423ce96ee5e6af6a4 Mon Sep 17 00:00:00 2001 From: Ian Lewis Date: Mon, 28 Oct 2019 01:32:30 -0400 Subject: [PATCH 2/9] Comment out unused references --- content/docs/user_guide/install.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/content/docs/user_guide/install.md b/content/docs/user_guide/install.md index 3b7e33dc2..cd6430a5e 100644 --- a/content/docs/user_guide/install.md +++ b/content/docs/user_guide/install.md @@ -164,7 +164,9 @@ optionally automatically configure Docker: runsc install ``` +[old-linux]: /docs/user_guide/networking/#gso + From 5e92b48511ce7321a5a73c78eb984c9b8119c2bb Mon Sep 17 00:00:00 2001 From: Ian Lewis Date: Fri, 17 Jan 2020 01:49:26 -0500 Subject: [PATCH 3/9] Added config for markdown linter * Support markdown footnotes * Don't complain about list indentation --- content/.remarkrc | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 content/.remarkrc diff --git a/content/.remarkrc b/content/.remarkrc new file mode 100644 index 000000000..b0dca57ce --- /dev/null +++ b/content/.remarkrc @@ -0,0 +1,9 @@ +{ + "settings": { + "footnotes": true + }, + "plugins": [ + "remark-preset-lint-recommended", + ["remark-lint-list-item-indent", false] + ] +} From 712a2829e75c7c8fce6a24df774ec38f72d14348 Mon Sep 17 00:00:00 2001 From: Ian Lewis Date: Fri, 17 Jan 2020 01:55:36 -0500 Subject: [PATCH 4/9] Fix extra spaces in footnotes --- content/blog/1_security_basics/index.md | 32 ++++++++----------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/content/blog/1_security_basics/index.md b/content/blog/1_security_basics/index.md index 9c24d81d1..cbcdc1b61 100644 --- a/content/blog/1_security_basics/index.md +++ b/content/blog/1_security_basics/index.md @@ -21,7 +21,7 @@ Future posts will address _resource efficiency_ (how gVisor preserves container Delivering on each of these goals requires careful security considerations and a robust design. -## What does “sandbox” mean? +## What does “sandbox" mean? gVisor allows the execution of untrusted containers, preventing them from adversely affecting the host. This means that the untrusted container is prevented from attacking or spying on either the host kernel or any other peer userspace processes on the host. @@ -62,7 +62,7 @@ In order to discuss design principles, the following components are important to It is important to emphasize what is being protected from the untrusted application in this diagram: the host OS and other userspace applications. -In this post, we are only discussing security-related features of gVisor, and you might ask, “What about performance, compatibility and stability?” We will cover these considerations in future posts. +In this post, we are only discussing security-related features of gVisor, and you might ask, “What about performance, compatibility and stability?" We will cover these considerations in future posts. ## Defense-in-Depth @@ -73,19 +73,7 @@ It may seem strange that we would want our own software components to distrust e And this leads us to how Defense-in-Depth is applied to gVisor: no single vulnerability should compromise the host. -In the “Attacker’s Advantage / Defender’s Dilemma,” the defender must succeed all the time while the attacker only needs to succeed once. Defense in Depth inverts this principle: once the attacker successfully compromises any given software component, they are immediately faced with needing to compromise a subsequent, distinct layer in order to move laterally or acquire more privilege. - -For example, the untrusted container is isolated from the Sentry. The Sentry is isolated from host I/O operations by serving those requests in separate processes called Gofers. And both the untrusted container and its associated Gofers are isolated from the host process that is running the sandbox. - -An additional benefit is that this generally leads to more robust and stable software, forcing interfaces to be strictly defined and tested to ensure all inputs are properly parsed and bounds checked. - - -## Least-Privilege - -The principle of Least-Privilege implies that each software component has only the permissions it needs to function, and no more. - -Least-Privilege is applied throughout gVisor. Each component and more importantly, each interface between the components, is designed so that only the minimum level of permission is required for it to perform its function. Specifically, the closer you are to the untrusted application, the less privilege you have. - +In the “Attacker’s Advantage / Defender’s Dilemm ____ ![Figure 2](./figure2.png) @@ -116,7 +104,7 @@ Furthermore, any exploited vulnerabilities in the implemented syscalls (or Sentr ### Sentry/Host OS Interface: -The Sentry’s interactions with the Host OS are restricted in many ways. For instance, no syscall is “passed-through” from the untrusted application to the host OS. All syscalls are intercepted and interpreted. In the case where the Sentry needs to call the Host OS, we severely limit the syscalls that the Sentry itself is allowed to make to the host kernel[^6]. +The Sentry’s interactions with the Host OS are restricted in many ways. For instance, no syscall is "passed-through" from the untrusted application to the host OS. All syscalls are intercepted and interpreted. In the case where the Sentry needs to call the Host OS, we severely limit the syscalls that the Sentry itself is allowed to make to the host kernel[^6]. For example, there are many file-system based attacks, where manipulation of files or their paths, can lead to compromise of the host[^7]. As a result, the Sentry does not allow any syscall that creates or opens a file descriptor. All file descriptors must be donated to the sandbox. By disallowing open or creation of file descriptors, we eliminate entire categories of these file-based attacks. @@ -161,11 +149,11 @@ At a higher level, boundaries in software might be describing a great many thing Security boundaries are interfaces that are designed and built so that entire classes of bugs/vulnerabilities are eliminated. -For example, the Sentry and Gofers are implemented using Go. Go was chosen for a number of the features it provided. Go is a fast, statically-typed, compiled language that has efficient multi-threading support, garbage collection and a constrained set of “unsafe” operations. +For example, the Sentry and Gofers are implemented using Go. Go was chosen for a number of the features it provided. Go is a fast, statically-typed, compiled language that has efficient multi-threading support, garbage collection and a constrained set of “unsafe" operations. Using these features enabled safe array and pointer handling. This means entire classes of vulnerabilities were eliminated, such as buffer overflows and use-after-free. -Another example is our use of very strict syscall switching to ensure that the Sentry is always the first software component that parses and interprets the calls being made by the untrusted container. Here is an instance where different platforms use different solutions, but all of them share this common trait, whether it is through the use of ptrace “a la PTRACE_ATTACH”[^11] or kvm’s ring0[^12]. +Another example is our use of very strict syscall switching to ensure that the Sentry is always the first software component that parses and interprets the calls being made by the untrusted container. Here is an instance where different platforms use different solutions, but all of them share this common trait, whether it is through the use of ptrace “a la PTRACE_ATTACH"[^11] or kvm’s ring0[^12]. Finally, one of the most restrictive choices was to use seccomp, to restrict the Sentry from being able to open or create a file descriptor on the host. All file I/O is required to go through Gofers. Preventing the opening or creation of file descriptions eliminates whole categories of bugs around file permissions [like this one](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-4557)[^13]. @@ -187,7 +175,7 @@ We will also use it to introduce Google’s Vulnerability Reward Program[^14], a [https://gvisor.dev/docs/architecture_guide](https://gvisor.dev/docs/architecture_guide/) [^3]: - [ https://github.com/google/gvisor/blob/master/pkg/sentry/syscalls/linux/linux64_amd64.go](https://github.com/google/gvisor/blob/master/pkg/sentry/syscalls/syscalls.go) + [https://github.com/google/gvisor/blob/master/pkg/sentry/syscalls/linux/linux64_amd64.go](https://github.com/google/gvisor/blob/master/pkg/sentry/syscalls/syscalls.go) [^4]: Internally that is, it doesn't call to the Host OS to implement them, in fact that is explicitly disallowed, more on that in the future. @@ -202,13 +190,13 @@ We will also use it to introduce Google’s Vulnerability Reward Program[^14], a [https://en.wikipedia.org/wiki/Dirty_COW](https://en.wikipedia.org/wiki/Dirty_COW) [^8]: - [ https://github.com/google/gvisor/blob/master/runsc/boot/config.go](https://github.com/google/gvisor/blob/master/runsc/boot/config.go) + [https://github.com/google/gvisor/blob/master/runsc/boot/config.go](https://github.com/google/gvisor/blob/master/runsc/boot/config.go) [^9]: [https://en.wikipedia.org/wiki/9P_(protocol)](https://en.wikipedia.org/wiki/9P_(protocol)) [^10]: - [ https://gvisor.dev/docs/user_guide/networking/#network-passthrough](https://gvisor.dev/docs/user_guide/networking/#network-passthrough) + [https://gvisor.dev/docs/user_guide/networking/#network-passthrough](https://gvisor.dev/docs/user_guide/networking/#network-passthrough) [^11]: [https://github.com/google/gvisor/blob/c7e901f47a09eaac56bd4813227edff016fa6bff/pkg/sentry/platform/ptrace/subprocess.go#L390](https://github.com/google/gvisor/blob/c7e901f47a09eaac56bd4813227edff016fa6bff/pkg/sentry/platform/ptrace/subprocess.go#L390) @@ -220,5 +208,5 @@ We will also use it to introduce Google’s Vulnerability Reward Program[^14], a [https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-4557](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-4557) [^14]: - [ https://www.google.com/about/appsecurity/reward-program/index.html](https://www.google.com/about/appsecurity/reward-program/index.html) + [https://www.google.com/about/appsecurity/reward-program/index.html](https://www.google.com/about/appsecurity/reward-program/index.html) From 10ec43c775afaa49ca638cd2d411e975e06dbe78 Mon Sep 17 00:00:00 2001 From: Ian Lewis Date: Fri, 17 Jan 2020 02:13:07 -0500 Subject: [PATCH 5/9] Clean up markdown lists --- content/docs/architecture_guide/overview.md | 6 +- content/docs/architecture_guide/security.md | 68 +++++++++---------- content/docs/community/_index.md | 4 +- content/docs/tutorials/kubernetes.md | 6 +- content/docs/user_guide/FAQ.md | 12 ++-- content/docs/user_guide/checkpoint_restore.md | 26 +++---- .../docs/user_guide/compatibility/_index.md | 8 +-- content/docs/user_guide/debugging.md | 8 +-- content/docs/user_guide/install.md | 6 +- content/docs/user_guide/platforms.md | 8 +-- content/docs/user_guide/quick_start/_index.md | 6 +- 11 files changed, 79 insertions(+), 79 deletions(-) diff --git a/content/docs/architecture_guide/overview.md b/content/docs/architecture_guide/overview.md index c12f9127f..50ef89c81 100644 --- a/content/docs/architecture_guide/overview.md +++ b/content/docs/architecture_guide/overview.md @@ -8,12 +8,12 @@ be run. Each sandbox has its own isolated instance of: -* The **Sentry**, A user-space kernel that runs the container and intercepts - and responds to system calls made by the application. +* The **Sentry**, A user-space kernel that runs the container and intercepts + and responds to system calls made by the application. Each container running in the sandbox has its own isolated instance of: -* A **Gofer** which provides file system access to the container. +* A **Gofer** which provides file system access to the container. ![gVisor architecture diagram](../Sentry-Gofer.png "gVisor architecture diagram") diff --git a/content/docs/architecture_guide/security.md b/content/docs/architecture_guide/security.md index 5084565e7..70c54bf95 100644 --- a/content/docs/architecture_guide/security.md +++ b/content/docs/architecture_guide/security.md @@ -32,9 +32,9 @@ are written in [C][clang], which is well-suited to interfacing with hardware but often prone to security issues. In order to exploit these issues, a typical attack might involve some combination of the following: -1. Opening or creating some combination of files, sockets or other descriptors. -1. Passing crafted, malicious arguments, structures or packets. -1. Racing with multiple threads in order to hit specific code paths. +1. Opening or creating some combination of files, sockets or other descriptors. +1. Passing crafted, malicious arguments, structures or packets. +1. Racing with multiple threads in order to hit specific code paths. For example, for the [Dirty Cow][dirtycow] privilege escalation bug, an application would open a specific file in `/proc` or use a specific `ptrace` @@ -140,15 +140,15 @@ filesystem attributes) and not underlying host system resources. While the sandbox virtualizes many operations for the application, we limit the sandbox's own interactions with the host to the following high-level operations: -1. Communicate with a Gofer process via a connected socket. The sandbox may - receive new file descriptors from the Gofer process, corresponding to opened - files. These files can then be read from and written to by the sandbox. -1. Make a minimal set of host system calls. The calls do not include the - creation of new sockets (unless host networking mode is enabled) or opening - files. The calls include duplication and closing of file descriptors, - synchronization, timers and signal management. -1. Read and write packets to a virtual ethernet device. This is not required if - host networking is enabled (or networking is disabled). +1. Communicate with a Gofer process via a connected socket. The sandbox may + receive new file descriptors from the Gofer process, corresponding to opened + files. These files can then be read from and written to by the sandbox. +1. Make a minimal set of host system calls. The calls do not include the + creation of new sockets (unless host networking mode is enabled) or opening + files. The calls include duplication and closing of file descriptors, + synchronization, timers and signal management. +1. Read and write packets to a virtual ethernet device. This is not required if + host networking is enabled (or networking is disabled). ### System ABI, Side Channels and Other Vectors @@ -173,32 +173,32 @@ less likely to exploit or override these controls through other means. For gVisor development, there are several engineering principles that are employed in order to ensure that the system meets its design goals. -1. No system call is passed through directly to the host. Every supported call - has an independent implementation in the Sentry, that is unlikely to suffer - from identical vulnerabilities that may appear in the host. This has the - consequence that all kernel features used by applications require an - implementation within the Sentry. -1. Only common, universal functionality is implemented. Some filesystems, - network devices or modules may expose specialized functionality to user - space applications via mechanisms such as extended attributes, raw sockets - or ioctls. Since the Sentry is responsible for implementing the full system - call surface, we do not implement or pass through these specialized APIs. -1. The host surface exposed to the Sentry is minimized. While the system call - surface is not trivial, it is explicitly enumerated and controlled. The - Sentry is not permitted to open new files, create new sockets or do many - other interesting things on the host. +1. No system call is passed through directly to the host. Every supported call + has an independent implementation in the Sentry, that is unlikely to suffer + from identical vulnerabilities that may appear in the host. This has the + consequence that all kernel features used by applications require an + implementation within the Sentry. +1. Only common, universal functionality is implemented. Some filesystems, + network devices or modules may expose specialized functionality to user + space applications via mechanisms such as extended attributes, raw sockets + or ioctls. Since the Sentry is responsible for implementing the full system + call surface, we do not implement or pass through these specialized APIs. +1. The host surface exposed to the Sentry is minimized. While the system call + surface is not trivial, it is explicitly enumerated and controlled. The + Sentry is not permitted to open new files, create new sockets or do many + other interesting things on the host. Additionally, we have practical restrictions that are imposed on the project to minimize the risk of Sentry exploitability. For example: -1. Unsafe code is carefully controlled. All unsafe code is isolated in files - that end with "unsafe.go", in order to facilitate validation and auditing. - No file without the unsafe suffix may import the unsafe package. -1. No CGo is allowed. The Sentry must be a pure Go binary. -1. External imports are not generally allowed within the core packages. Only - limited external imports are used within the setup code. The code available - inside the Sentry is carefully controlled, to ensure that the above rules - are effective. +1. Unsafe code is carefully controlled. All unsafe code is isolated in files + that end with "unsafe.go", in order to facilitate validation and auditing. + No file without the unsafe suffix may import the unsafe package. +1. No CGo is allowed. The Sentry must be a pure Go binary. +1. External imports are not generally allowed within the core packages. Only + limited external imports are used within the setup code. The code available + inside the Sentry is carefully controlled, to ensure that the above rules + are effective. Finally, we recognize that security is a process, and that vigilance is critical. Beyond our security disclosure process, the Sentry is fuzzed diff --git a/content/docs/community/_index.md b/content/docs/community/_index.md index 09e8f5573..0f493c15a 100644 --- a/content/docs/community/_index.md +++ b/content/docs/community/_index.md @@ -9,8 +9,8 @@ repositories have their own guidelines and processes for contributing. See the The project maintains two mailing lists: -* [gvisor-users][gvisor-users] for accouncements and general discussion. -* [gvisor-dev][gvisor-dev] for development and contribution. +* [gvisor-users][gvisor-users] for accouncements and general discussion. +* [gvisor-dev][gvisor-dev] for development and contribution. We also have a [chat room hosted on Gitter][gitter-chat]. diff --git a/content/docs/tutorials/kubernetes.md b/content/docs/tutorials/kubernetes.md index 36ab59c1c..5b65ba20f 100644 --- a/content/docs/tutorials/kubernetes.md +++ b/content/docs/tutorials/kubernetes.md @@ -12,9 +12,9 @@ This page shows you how to deploy a sample [WordPress][wordpress] site using Take the following steps to enable the Kubernetes Engine API: -1. Visit the [Kubernetes Engine page][project-selector] in the Google Cloud - Platform Console. -1. Create or select a project. +1. Visit the [Kubernetes Engine page][project-selector] in the Google Cloud + Platform Console. +1. Create or select a project. ### Creating a node pool with gVisor enabled diff --git a/content/docs/user_guide/FAQ.md b/content/docs/user_guide/FAQ.md index da742a41b..74acaa125 100644 --- a/content/docs/user_guide/FAQ.md +++ b/content/docs/user_guide/FAQ.md @@ -89,12 +89,12 @@ order to communicate to the DNS server. runsc network is isolated from the host and cannot access the DNS server on the host network without breaking the sandbox isolation. There are a few different workarounds you can try: -* Use default bridge network with `--link` to connect containers. Default - bridge doesn't use embedded DNS. -* Use [`--network=host`][host-net] option in runsc, however beware that it will - use the host network stack and is less secure. -* Use IPs instead of container names. -* Use [Kubernetes][k8s]. Container name lookup works fine in Kubernetes. +* Use default bridge network with `--link` to connect containers. Default + bridge doesn't use embedded DNS. +* Use [`--network=host`][host-net] option in runsc, however beware that it will + use the host network stack and is less secure. +* Use IPs instead of container names. +* Use [Kubernetes][k8s]. Container name lookup works fine in Kubernetes. [security-model]: /docs/architecture_guide/security/ [old-linux]: /docs/user_guide/networking/#gso diff --git a/content/docs/user_guide/checkpoint_restore.md b/content/docs/user_guide/checkpoint_restore.md index f13c5199e..fef4c1dfa 100644 --- a/content/docs/user_guide/checkpoint_restore.md +++ b/content/docs/user_guide/checkpoint_restore.md @@ -83,19 +83,19 @@ docker start --checkpoint --checkpoint-dir= ### Issues Preventing Compatibility with Docker -* **[Moby #37360][leave-running]:** Docker version 18.03.0-ce and earlier hangs - when checkpointing and does not create the checkpoint. To successfully use - this feature, install a custom version of docker-ce from the moby repository. - This issue is caused by an improper implementation of the `--leave-running` - flag. This issue is fixed in newer releases. -* **Docker does not support restoration into new containers:** Docker currently - expects the container which created the checkpoint to be the same container - used to restore which is not possible in runsc. When Docker supports container - migration and therefore restoration into new containers, this will be the - flow. -* **[Moby #37344][checkpoint-dir]:** Docker does not currently support the - `--checkpoint-dir` flag but this will be required when restoring from a - checkpoint made in another container. +- **[Moby #37360][leave-running]:** Docker version 18.03.0-ce and earlier hangs + when checkpointing and does not create the checkpoint. To successfully use + this feature, install a custom version of docker-ce from the moby repository. + This issue is caused by an improper implementation of the `--leave-running` + flag. This issue is fixed in newer releases. +- **Docker does not support restoration into new containers:** Docker currently + expects the container which created the checkpoint to be the same container + used to restore which is not possible in runsc. When Docker supports container + migration and therefore restoration into new containers, this will be the + flow. +- **[Moby #37344][checkpoint-dir]:** Docker does not currently support the + `--checkpoint-dir` flag but this will be required when restoring from a + checkpoint made in another container. [leave-running]: https://github.com/moby/moby/pull/37360 [checkpoint-dir]: https://github.com/moby/moby/issues/37344 diff --git a/content/docs/user_guide/compatibility/_index.md b/content/docs/user_guide/compatibility/_index.md index ff0e6acce..94fcb6f22 100644 --- a/content/docs/user_guide/compatibility/_index.md +++ b/content/docs/user_guide/compatibility/_index.md @@ -40,10 +40,10 @@ The following applications/images have been tested: Most common utilities work. Note that: -* Some tools, such as `tcpdump` and old versions of `ping`, require explicitly - enabling raw sockets via the unsafe `--net-raw` runsc flag. -* Different Docker images can behave differently. For example, Alpine Linux and - Ubuntu have different `ip` binaries. +* Some tools, such as `tcpdump` and old versions of `ping`, require explicitly + enabling raw sockets via the unsafe `--net-raw` runsc flag. +* Different Docker images can behave differently. For example, Alpine Linux and + Ubuntu have different `ip` binaries. Specific tools include: diff --git a/content/docs/user_guide/debugging.md b/content/docs/user_guide/debugging.md index c19269934..49f9638d7 100644 --- a/content/docs/user_guide/debugging.md +++ b/content/docs/user_guide/debugging.md @@ -106,9 +106,9 @@ Then restart docker to refresh the runtime options. While the container is runni execute `runsc debug` to collect profile information and save to a file. Here are the options available: -* **--profile-heap:** Generates heap profile to the speficied file. -* **--profile-cpu:** Enables CPU profiler, waits for `--profile-delay` seconds - and generates CPU profile to the speficied file. +* **--profile-heap:** Generates heap profile to the speficied file. +* **--profile-cpu:** Enables CPU profiler, waits for `--profile-delay` seconds + and generates CPU profile to the speficied file. For example: @@ -120,7 +120,7 @@ sudo runsc --root /var/run/docker/runtime-runsc-prof/moby debug --profile-heap=/ sudo runsc --root /var/run/docker/runtime-runsc-prof/moby debug --profile-cpu=/tmp/cpu.prof --profile-delay=30 63254c6ab3a6989623fa1fb53616951eed31ac605a2637bb9ddba5d8d404b35b ``` -The resulting files can be opened using `go tool pprof` or [pprof][pprof]. The examples +The resulting files can be opened using `go tool pprof` or [pprof][]. The examples below create image file (`.svg`) with the heap profile and writes the top functions using CPU to the console: diff --git a/content/docs/user_guide/install.md b/content/docs/user_guide/install.md index d1bf79dd5..f25bc0d73 100644 --- a/content/docs/user_guide/install.md +++ b/content/docs/user_guide/install.md @@ -102,9 +102,9 @@ Based on the release type, you will need to substitute `${DIST}` below, using one of: * `master`: For HEAD. -* `nightly: For nightly releases. -* `release: For the latest release. -* `${yyyymmdd}: For a specific releases (see above). +* `nightly`: For nightly releases. +* `release`: For the latest release. +* `${yyyymmdd}`: For a specific releases (see above). The repository for the release you wish to install should be added: diff --git a/content/docs/user_guide/platforms.md b/content/docs/user_guide/platforms.md index 72e640cc8..b0b76c0ee 100644 --- a/content/docs/user_guide/platforms.md +++ b/content/docs/user_guide/platforms.md @@ -58,10 +58,10 @@ If you are using a virtual machine you will need to make sure that nested virtualization is configured. Here are links to documents on how to set up nested virtualization in several popular environments: -* Google Cloud: [Enabling Nested Virtualization for VM Instances][nested-gcp] -* Microsoft Azure: [How to enable nested virtualization in an Azure VM][nested-azure] -* VirtualBox: [Nested Virtualization][nested-virtualbox] -* KVM: [Nested Guests][nested-kvm] +* Google Cloud: [Enabling Nested Virtualization for VM Instances][nested-gcp] +* Microsoft Azure: [How to enable nested virtualization in an Azure VM][nested-azure] +* VirtualBox: [Nested Virtualization][nested-virtualbox] +* KVM: [Nested Guests][nested-kvm] ### Configuring Docker diff --git a/content/docs/user_guide/quick_start/_index.md b/content/docs/user_guide/quick_start/_index.md index bb35e748f..3d1524bc8 100644 --- a/content/docs/user_guide/quick_start/_index.md +++ b/content/docs/user_guide/quick_start/_index.md @@ -7,6 +7,6 @@ gVisor can be used with Docker, Kubernetes, or directly using `runsc` with crafted OCI spec for your container. Use the links below to see detailed instructions for each of them: -* [Docker](./docker/): The quickest and easiest way to get started. -* [Kubernetes](./kubernetes/): Isolate Pods in your K8s cluster with gVisor. -* [OCI](./oci/): Expert mode. Customize gVisor for your environment. +* [Docker](./docker/): The quickest and easiest way to get started. +* [Kubernetes](./kubernetes/): Isolate Pods in your K8s cluster with gVisor. +* [OCI](./oci/): Expert mode. Customize gVisor for your environment. From fd0628b5f565f24cf4145065e404bf5f40aa265f Mon Sep 17 00:00:00 2001 From: Ian Lewis Date: Fri, 17 Jan 2020 02:27:50 -0500 Subject: [PATCH 6/9] Dedup check command --- Makefile | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 22b8fd3d7..9abdcfc3e 100644 --- a/Makefile +++ b/Makefile @@ -106,9 +106,6 @@ compatibility-docs: bin/generate-syscall-docs upstream/gvisor/bazel-bin/runsc/li .PHONY: compatibility-docs check: check-markdown check-html - docker run \ - -v $(shell pwd)/public:/public gcr.io/gvisor-website/html-proofer:$(HTMLPROOFER_VERSION) \ - htmlproofer --disable-external --check-html public/static .PHONY: check check-markdown: node_modules $(CONTENT_SOURCE) compatibility-docs @@ -125,7 +122,9 @@ check-markdown: node_modules $(CONTENT_SOURCE) compatibility-docs .PHONY: check-markdown check-html: website - docker run -v $(shell pwd)/public:/public gcr.io/gvisor-website/html-proofer:3.10.2 htmlproofer --disable-external --check-html public/static + docker run \ + -v $(shell pwd)/public:/public gcr.io/gvisor-website/html-proofer:$(HTMLPROOFER_VERSION) \ + htmlproofer --disable-external --check-html public/static .PHONY: check-html # Run a local content development server. Redirects will not be supported. From ab86e608709e18df77950aa2f731fbb428464965 Mon Sep 17 00:00:00 2001 From: Ian Lewis Date: Fri, 17 Jan 2020 02:28:41 -0500 Subject: [PATCH 7/9] Fix quotes in blog post --- content/blog/1_security_basics/index.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/content/blog/1_security_basics/index.md b/content/blog/1_security_basics/index.md index cbcdc1b61..afbd6ca7e 100644 --- a/content/blog/1_security_basics/index.md +++ b/content/blog/1_security_basics/index.md @@ -21,7 +21,7 @@ Future posts will address _resource efficiency_ (how gVisor preserves container Delivering on each of these goals requires careful security considerations and a robust design. -## What does “sandbox" mean? +## What does "sandbox" mean? gVisor allows the execution of untrusted containers, preventing them from adversely affecting the host. This means that the untrusted container is prevented from attacking or spying on either the host kernel or any other peer userspace processes on the host. @@ -62,7 +62,7 @@ In order to discuss design principles, the following components are important to It is important to emphasize what is being protected from the untrusted application in this diagram: the host OS and other userspace applications. -In this post, we are only discussing security-related features of gVisor, and you might ask, “What about performance, compatibility and stability?" We will cover these considerations in future posts. +In this post, we are only discussing security-related features of gVisor, and you might ask, "What about performance, compatibility and stability?" We will cover these considerations in future posts. ## Defense-in-Depth @@ -73,7 +73,7 @@ It may seem strange that we would want our own software components to distrust e And this leads us to how Defense-in-Depth is applied to gVisor: no single vulnerability should compromise the host. -In the “Attacker’s Advantage / Defender’s Dilemm +In the "Attacker’s Advantage / Defender’s Dilemm ____ ![Figure 2](./figure2.png) @@ -149,11 +149,11 @@ At a higher level, boundaries in software might be describing a great many thing Security boundaries are interfaces that are designed and built so that entire classes of bugs/vulnerabilities are eliminated. -For example, the Sentry and Gofers are implemented using Go. Go was chosen for a number of the features it provided. Go is a fast, statically-typed, compiled language that has efficient multi-threading support, garbage collection and a constrained set of “unsafe" operations. +For example, the Sentry and Gofers are implemented using Go. Go was chosen for a number of the features it provided. Go is a fast, statically-typed, compiled language that has efficient multi-threading support, garbage collection and a constrained set of "unsafe" operations. Using these features enabled safe array and pointer handling. This means entire classes of vulnerabilities were eliminated, such as buffer overflows and use-after-free. -Another example is our use of very strict syscall switching to ensure that the Sentry is always the first software component that parses and interprets the calls being made by the untrusted container. Here is an instance where different platforms use different solutions, but all of them share this common trait, whether it is through the use of ptrace “a la PTRACE_ATTACH"[^11] or kvm’s ring0[^12]. +Another example is our use of very strict syscall switching to ensure that the Sentry is always the first software component that parses and interprets the calls being made by the untrusted container. Here is an instance where different platforms use different solutions, but all of them share this common trait, whether it is through the use of ptrace "a la PTRACE_ATTACH"[^11] or kvm’s ring0[^12]. Finally, one of the most restrictive choices was to use seccomp, to restrict the Sentry from being able to open or create a file descriptor on the host. All file I/O is required to go through Gofers. Preventing the opening or creation of file descriptions eliminates whole categories of bugs around file permissions [like this one](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-4557)[^13]. From cac45fb387be62458603d6de261ceb0b70e3e8cd Mon Sep 17 00:00:00 2001 From: Ian Lewis Date: Fri, 17 Jan 2020 02:34:53 -0500 Subject: [PATCH 8/9] Fixed blog post markdown --- content/blog/1_security_basics/index.md | 34 +++++++++++++++++-------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/content/blog/1_security_basics/index.md b/content/blog/1_security_basics/index.md index afbd6ca7e..5d6e82be0 100644 --- a/content/blog/1_security_basics/index.md +++ b/content/blog/1_security_basics/index.md @@ -10,7 +10,7 @@ author: Jeremiah Spradlin & Zach Koopmans This blog is a space for engineers and community members to share perspectives and deep dives on technology and design within the gVisor project. -Though our logo suggests we’re in the business of space exploration (or perhaps fighting sea monsters), we’re actually in the business of sandboxing Linux containers. +Though our logo suggests we're in the business of space exploration (or perhaps fighting sea monsters), we're actually in the business of sandboxing Linux containers. When we created gVisor, we had three specific goals in mind; _container-native security_, _resource efficiency_, and _platform portability_. To put it simply, gVisor provides _efficient defense-in-depth for containers anywhere_. @@ -32,7 +32,7 @@ For example, if you are a cloud container hosting service, running containers fr gVisor was designed around the premise that any security boundary could potentially be compromised with enough time and resources. We tried to optimize for a solution that was as costly and time-consuming for an attacker as possible, at every layer. -Consequently, gVisor was built through a combination of intentional design principles and specific technology choices that work together to provide the security isolation needed for running hostile containers on a host. We’ll dig into it in the next section! +Consequently, gVisor was built through a combination of intentional design principles and specific technology choices that work together to provide the security isolation needed for running hostile containers on a host. We'll dig into it in the next section! # Design Principles @@ -73,7 +73,19 @@ It may seem strange that we would want our own software components to distrust e And this leads us to how Defense-in-Depth is applied to gVisor: no single vulnerability should compromise the host. -In the "Attacker’s Advantage / Defender’s Dilemm +In the "Attacker's Advantage / Defender's Dilemma," the defender must succeed all the time while the attacker only needs to succeed once. Defense in Depth inverts this principle: once the attacker successfully compromises any given software component, they are immediately faced with needing to compromise a subsequent, distinct layer in order to move laterally or acquire more privilege. + +For example, the untrusted container is isolated from the Sentry. The Sentry is isolated from host I/O operations by serving those requests in separate processes called Gofers. And both the untrusted container and its associated Gofers are isolated from the host process that is running the sandbox. + +An additional benefit is that this generally leads to more robust and stable software, forcing interfaces to be strictly defined and tested to ensure all inputs are properly parsed and bounds checked. + + +## Least-Privilege + +The principle of Least-Privilege implies that each software component has only the permissions it needs to function, and no more. + +Least-Privilege is applied throughout gVisor. Each component and more importantly, each interface between the components, is designed so that only the minimum level of permission is required for it to perform its function. Specifically, the closer you are to the untrusted application, the less privilege you have. + ____ ![Figure 2](./figure2.png) @@ -81,7 +93,7 @@ ____ Figure 2: runsc components and their privileges. ____ -This is evident in how runsc (the drop in gVisor binary for Docker/Kubernetes) constructs the sandbox. The Sentry has the least privilege possible (it can’t even open a file!). Gofers are only allowed file access, so even if it were compromised, the host network would be unavailable. Only the runsc binary itself has full access to the host OS, and even runsc’s access to the host OS is often limited through capabilities / chroot / namespacing. +This is evident in how runsc (the drop in gVisor binary for Docker/Kubernetes) constructs the sandbox. The Sentry has the least privilege possible (it can't even open a file!). Gofers are only allowed file access, so even if it were compromised, the host network would be unavailable. Only the runsc binary itself has full access to the host OS, and even runsc's access to the host OS is often limited through capabilities / chroot / namespacing. Designing a system with Defense-in-Depth and Least-Privilege in mind encourages small, separate, single-purpose components, each with very restricted privileges. @@ -104,7 +116,7 @@ Furthermore, any exploited vulnerabilities in the implemented syscalls (or Sentr ### Sentry/Host OS Interface: -The Sentry’s interactions with the Host OS are restricted in many ways. For instance, no syscall is "passed-through" from the untrusted application to the host OS. All syscalls are intercepted and interpreted. In the case where the Sentry needs to call the Host OS, we severely limit the syscalls that the Sentry itself is allowed to make to the host kernel[^6]. +The Sentry's interactions with the Host OS are restricted in many ways. For instance, no syscall is "passed-through" from the untrusted application to the host OS. All syscalls are intercepted and interpreted. In the case where the Sentry needs to call the Host OS, we severely limit the syscalls that the Sentry itself is allowed to make to the host kernel[^6]. For example, there are many file-system based attacks, where manipulation of files or their paths, can lead to compromise of the host[^7]. As a result, the Sentry does not allow any syscall that creates or opens a file descriptor. All file descriptors must be donated to the sandbox. By disallowing open or creation of file descriptors, we eliminate entire categories of these file-based attacks. @@ -153,16 +165,16 @@ For example, the Sentry and Gofers are implemented using Go. Go was chosen for a Using these features enabled safe array and pointer handling. This means entire classes of vulnerabilities were eliminated, such as buffer overflows and use-after-free. -Another example is our use of very strict syscall switching to ensure that the Sentry is always the first software component that parses and interprets the calls being made by the untrusted container. Here is an instance where different platforms use different solutions, but all of them share this common trait, whether it is through the use of ptrace "a la PTRACE_ATTACH"[^11] or kvm’s ring0[^12]. +Another example is our use of very strict syscall switching to ensure that the Sentry is always the first software component that parses and interprets the calls being made by the untrusted container. Here is an instance where different platforms use different solutions, but all of them share this common trait, whether it is through the use of ptrace "a la PTRACE_ATTACH"[^11] or kvm's ring0[^12]. Finally, one of the most restrictive choices was to use seccomp, to restrict the Sentry from being able to open or create a file descriptor on the host. All file I/O is required to go through Gofers. Preventing the opening or creation of file descriptions eliminates whole categories of bugs around file permissions [like this one](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-4557)[^13]. # To be continued - Part 2 -In part 2 of this blog post, we will explore gVisor from an attacker’s point of view. We will use it as an opportunity to examine the specific strengths and weaknesses of each gVisor component. +In part 2 of this blog post, we will explore gVisor from an attacker's point of view. We will use it as an opportunity to examine the specific strengths and weaknesses of each gVisor component. -We will also use it to introduce Google’s Vulnerability Reward Program[^14], and other ways the community can contribute to help make gVisor safe, fast and stable. +We will also use it to introduce Google's Vulnerability Reward Program[^14], and other ways the community can contribute to help make gVisor safe, fast and stable. @@ -202,11 +214,11 @@ We will also use it to introduce Google’s Vulnerability Reward Program[^14], a [https://github.com/google/gvisor/blob/c7e901f47a09eaac56bd4813227edff016fa6bff/pkg/sentry/platform/ptrace/subprocess.go#L390](https://github.com/google/gvisor/blob/c7e901f47a09eaac56bd4813227edff016fa6bff/pkg/sentry/platform/ptrace/subprocess.go#L390) [^12]: - [https://github.com/google/gvisor/blob/c7e901f47a09eaac56bd4813227edff016fa6bff/pkg/sentry/platform/ring0/kernel_amd64.go#L182](https://github.com/google/gvisor/blob/c7e901f47a09eaac56bd4813227edff016fa6bff/pkg/sentry/platform/ring0/kernel_amd64.go#L182) + [https://github.com/google/gvisor/blob/c7e901f47a09eaac56bd4813227edff016fa6bff/pkg/sentry/platform/ring0/kernel_amd64.go#L182](https://github.com/google/gvisor/blob/c7e901f47a09eaac56bd4813227edff016fa6bff/pkg/sentry/platform/ring0/kernel_amd64.go#L182) [^13]: - [https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-4557](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-4557) + [https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-4557](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-4557) [^14]: - [https://www.google.com/about/appsecurity/reward-program/index.html](https://www.google.com/about/appsecurity/reward-program/index.html) + [https://www.google.com/about/appsecurity/reward-program/index.html](https://www.google.com/about/appsecurity/reward-program/index.html) From 3bdcdb0097d4a1d499d78c9e5a50dab2e1a01e0a Mon Sep 17 00:00:00 2001 From: Ian Lewis Date: Fri, 17 Jan 2020 02:40:46 -0500 Subject: [PATCH 9/9] Dedup remark config --- content/.remarkrc | 9 --------- package.json | 6 +++++- 2 files changed, 5 insertions(+), 10 deletions(-) delete mode 100644 content/.remarkrc diff --git a/content/.remarkrc b/content/.remarkrc deleted file mode 100644 index b0dca57ce..000000000 --- a/content/.remarkrc +++ /dev/null @@ -1,9 +0,0 @@ -{ - "settings": { - "footnotes": true - }, - "plugins": [ - "remark-preset-lint-recommended", - ["remark-lint-list-item-indent", false] - ] -} diff --git a/package.json b/package.json index e9e0461b3..c52e26d82 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,12 @@ "lint-md": "remark ./content -f" }, "remarkConfig": { + "settings": { + "footnotes": true + }, "plugins": [ - "remark-preset-lint-recommended" + "remark-preset-lint-recommended", + ["remark-lint-list-item-indent", false] ] } }