@intentius/chant-lexicon-docker 0.124.21 → 0.124.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/dist/codegen/docs.d.ts.map +1 -1
  2. package/dist/codegen/generate.d.ts.map +1 -1
  3. package/dist/dockerfile-order.d.ts +13 -0
  4. package/dist/dockerfile-order.d.ts.map +1 -0
  5. package/dist/generated/index.d.ts +703 -6
  6. package/dist/generated/index.d.ts.map +1 -1
  7. package/dist/import/adapter.d.ts.map +1 -1
  8. package/dist/import/parser.d.ts +23 -0
  9. package/dist/import/parser.d.ts.map +1 -1
  10. package/dist/integrity.json +17 -8
  11. package/dist/lint/audit-catalog.d.ts.map +1 -1
  12. package/dist/lint/audit-lineage.d.ts.map +1 -1
  13. package/dist/lint/post-synth/add-url-checksum.d.ts +9 -0
  14. package/dist/lint/post-synth/add-url-checksum.d.ts.map +1 -0
  15. package/dist/lint/post-synth/apt-update-alone.d.ts +10 -0
  16. package/dist/lint/post-synth/apt-update-alone.d.ts.map +1 -0
  17. package/dist/lint/post-synth/cache-busting-copy.d.ts +11 -0
  18. package/dist/lint/post-synth/cache-busting-copy.d.ts.map +1 -0
  19. package/dist/lint/post-synth/copy-from-stage.d.ts +10 -0
  20. package/dist/lint/post-synth/copy-from-stage.d.ts.map +1 -0
  21. package/dist/lint/post-synth/docker-helpers.d.ts +35 -0
  22. package/dist/lint/post-synth/docker-helpers.d.ts.map +1 -1
  23. package/dist/lint/post-synth/index.d.ts.map +1 -1
  24. package/dist/lint/post-synth/no-root-user.d.ts +3 -2
  25. package/dist/lint/post-synth/no-root-user.d.ts.map +1 -1
  26. package/dist/lint/post-synth/relative-workdir.d.ts +10 -0
  27. package/dist/lint/post-synth/relative-workdir.d.ts.map +1 -0
  28. package/dist/lint/post-synth/repeated-cmd.d.ts +9 -0
  29. package/dist/lint/post-synth/repeated-cmd.d.ts.map +1 -0
  30. package/dist/lint/post-synth/root-after-user.d.ts +10 -0
  31. package/dist/lint/post-synth/root-after-user.d.ts.map +1 -0
  32. package/dist/lint/post-synth/unused-global-arg.d.ts +10 -0
  33. package/dist/lint/post-synth/unused-global-arg.d.ts.map +1 -0
  34. package/dist/lint/rules/index.d.ts +1 -0
  35. package/dist/lint/rules/index.d.ts.map +1 -1
  36. package/dist/lint/rules/per-kind-order.d.ts +15 -0
  37. package/dist/lint/rules/per-kind-order.d.ts.map +1 -0
  38. package/dist/manifest.json +1 -1
  39. package/dist/meta.json +444 -86
  40. package/dist/okf/index.md +10 -1
  41. package/dist/okf/rules/DKRD012.md +2 -2
  42. package/dist/okf/rules/DKRD013.md +11 -0
  43. package/dist/okf/rules/DKRD014.md +11 -0
  44. package/dist/okf/rules/DKRD015.md +11 -0
  45. package/dist/okf/rules/DKRD016.md +11 -0
  46. package/dist/okf/rules/DKRD017.md +11 -0
  47. package/dist/okf/rules/DKRD018.md +11 -0
  48. package/dist/okf/rules/DKRD019.md +11 -0
  49. package/dist/okf/rules/DKRD020.md +11 -0
  50. package/dist/okf/rules/DKRS002.md +15 -0
  51. package/dist/okf/types/DockerConfig.md +7 -5
  52. package/dist/okf/types/DockerSecret.md +8 -4
  53. package/dist/okf/types/Dockerfile.md +4 -1
  54. package/dist/okf/types/Network.md +10 -6
  55. package/dist/okf/types/Service.md +93 -15
  56. package/dist/okf/types/Volume.md +5 -5
  57. package/dist/plugin.d.ts.map +1 -1
  58. package/dist/rules/add-url-checksum.ts +38 -0
  59. package/dist/rules/apt-update-alone.ts +39 -0
  60. package/dist/rules/cache-busting-copy.ts +65 -0
  61. package/dist/rules/copy-from-stage.ts +54 -0
  62. package/dist/rules/docker-helpers.ts +80 -0
  63. package/dist/rules/no-root-user.ts +19 -17
  64. package/dist/rules/per-kind-order.ts +130 -0
  65. package/dist/rules/relative-workdir.ts +38 -0
  66. package/dist/rules/repeated-cmd.ts +35 -0
  67. package/dist/rules/root-after-user.ts +44 -0
  68. package/dist/rules/unused-global-arg.ts +38 -0
  69. package/dist/serializer.d.ts.map +1 -1
  70. package/dist/skills/chant-docker-patterns.md +93 -24
  71. package/dist/skills/chant-docker.md +43 -16
  72. package/dist/spec/parse-compose.d.ts +29 -2
  73. package/dist/spec/parse-compose.d.ts.map +1 -1
  74. package/dist/spec/parse-engine.d.ts +9 -0
  75. package/dist/spec/parse-engine.d.ts.map +1 -1
  76. package/dist/types/index.d.ts +344 -41
  77. package/package.json +3 -3
  78. package/src/codegen/__snapshots__/okf.test.ts.snap +278 -39
  79. package/src/codegen/docs.ts +14 -0
  80. package/src/codegen/generate.ts +128 -31
  81. package/src/codegen/okf.test.ts +1 -1
  82. package/src/dockerfile-order.ts +20 -0
  83. package/src/docs-examples.test.ts +141 -0
  84. package/src/generated/index.d.ts +344 -41
  85. package/src/generated/index.ts +396 -6
  86. package/src/generated/lexicon-docker.json +444 -86
  87. package/src/import/adapter.ts +8 -2
  88. package/src/import/generator.test.ts +4 -4
  89. package/src/import/generator.ts +53 -37
  90. package/src/import/parser.ts +82 -13
  91. package/src/import/roundtrip.test.ts +167 -2
  92. package/src/import/testdata/configs-secrets.yaml +15 -0
  93. package/src/lint/audit-catalog.ts +9 -1
  94. package/src/lint/audit-lineage.ts +14 -0
  95. package/src/lint/post-synth/add-url-checksum.ts +38 -0
  96. package/src/lint/post-synth/apt-update-alone.ts +39 -0
  97. package/src/lint/post-synth/cache-busting-copy.ts +65 -0
  98. package/src/lint/post-synth/copy-from-stage.ts +54 -0
  99. package/src/lint/post-synth/docker-helpers.ts +80 -0
  100. package/src/lint/post-synth/index.ts +16 -0
  101. package/src/lint/post-synth/no-root-user.ts +19 -17
  102. package/src/lint/post-synth/post-synth.test.ts +149 -0
  103. package/src/lint/post-synth/relative-workdir.ts +38 -0
  104. package/src/lint/post-synth/repeated-cmd.ts +35 -0
  105. package/src/lint/post-synth/root-after-user.ts +44 -0
  106. package/src/lint/post-synth/unused-global-arg.ts +38 -0
  107. package/src/lint/rules/index.ts +1 -0
  108. package/src/lint/rules/per-kind-order.ts +130 -0
  109. package/src/lint/rules/rules.test.ts +88 -0
  110. package/src/plugin.test.ts +4 -0
  111. package/src/plugin.ts +2 -1
  112. package/src/serializer.test.ts +112 -0
  113. package/src/serializer.ts +58 -11
  114. package/src/skills/chant-docker-patterns.md +93 -24
  115. package/src/skills/chant-docker.md +43 -16
  116. package/src/spec/parse-compose.ts +167 -95
  117. package/src/spec/parse-engine.ts +17 -5
  118. package/src/typecheck.e2e.test.ts +107 -0
  119. package/src/typed-props.test.ts +60 -0
@@ -1,14 +1,14 @@
1
1
  ---
2
2
  type: post-synth-check
3
3
  title: DKRD012
4
- description: Dockerfile has no USER instruction — container runs as root
4
+ description: Dockerfile's final stage has no USER instruction, or ends on USER root — container runs as root
5
5
  id: DKRD012
6
6
  severity: error
7
7
  category: post-synth
8
8
  lexicon: docker
9
9
  docs: https://intentius.io/chant/lexicons/docker/rules/
10
10
  ---
11
- Dockerfile has no USER instruction — container runs as root
11
+ Dockerfile's final stage has no USER instruction, or ends on USER root — container runs as root
12
12
 
13
13
  ## Applies to
14
14
 
@@ -0,0 +1,11 @@
1
+ ---
2
+ type: post-synth-check
3
+ title: DKRD013
4
+ description: Whole build context copied before a dependency install — every source change re-runs the install
5
+ id: DKRD013
6
+ severity: error
7
+ category: post-synth
8
+ lexicon: docker
9
+ docs: https://intentius.io/chant/lexicons/docker/rules/
10
+ ---
11
+ Whole build context copied before a dependency install — every source change re-runs the install
@@ -0,0 +1,11 @@
1
+ ---
2
+ type: post-synth-check
3
+ title: DKRD014
4
+ description: RUN needs root but comes after USER switched to a non-root user
5
+ id: DKRD014
6
+ severity: error
7
+ category: post-synth
8
+ lexicon: docker
9
+ docs: https://intentius.io/chant/lexicons/docker/rules/
10
+ ---
11
+ RUN needs root but comes after USER switched to a non-root user
@@ -0,0 +1,11 @@
1
+ ---
2
+ type: post-synth-check
3
+ title: DKRD015
4
+ description: More than one CMD or ENTRYPOINT in a stage — only the last one takes effect
5
+ id: DKRD015
6
+ severity: error
7
+ category: post-synth
8
+ lexicon: docker
9
+ docs: https://intentius.io/chant/lexicons/docker/rules/
10
+ ---
11
+ More than one CMD or ENTRYPOINT in a stage — only the last one takes effect
@@ -0,0 +1,11 @@
1
+ ---
2
+ type: post-synth-check
3
+ title: DKRD016
4
+ description: COPY --from names a stage that is not defined before it
5
+ id: DKRD016
6
+ severity: error
7
+ category: post-synth
8
+ lexicon: docker
9
+ docs: https://intentius.io/chant/lexicons/docker/rules/
10
+ ---
11
+ COPY --from names a stage that is not defined before it
@@ -0,0 +1,11 @@
1
+ ---
2
+ type: post-synth-check
3
+ title: DKRD017
4
+ description: ARG before the first FROM is not used by any FROM or stage
5
+ id: DKRD017
6
+ severity: error
7
+ category: post-synth
8
+ lexicon: docker
9
+ docs: https://intentius.io/chant/lexicons/docker/rules/
10
+ ---
11
+ ARG before the first FROM is not used by any FROM or stage
@@ -0,0 +1,11 @@
1
+ ---
2
+ type: post-synth-check
3
+ title: DKRD018
4
+ description: Relative WORKDIR before any absolute WORKDIR in the stage
5
+ id: DKRD018
6
+ severity: error
7
+ category: post-synth
8
+ lexicon: docker
9
+ docs: https://intentius.io/chant/lexicons/docker/rules/
10
+ ---
11
+ Relative WORKDIR before any absolute WORKDIR in the stage
@@ -0,0 +1,11 @@
1
+ ---
2
+ type: post-synth-check
3
+ title: DKRD019
4
+ description: ADD fetches a remote URL without --checksum
5
+ id: DKRD019
6
+ severity: error
7
+ category: post-synth
8
+ lexicon: docker
9
+ docs: https://intentius.io/chant/lexicons/docker/rules/
10
+ ---
11
+ ADD fetches a remote URL without --checksum
@@ -0,0 +1,11 @@
1
+ ---
2
+ type: post-synth-check
3
+ title: DKRD020
4
+ description: apt-get update in a different RUN from apt-get install — the install can use a stale package index
5
+ id: DKRD020
6
+ severity: error
7
+ category: post-synth
8
+ lexicon: docker
9
+ docs: https://intentius.io/chant/lexicons/docker/rules/
10
+ ---
11
+ apt-get update in a different RUN from apt-get install — the install can use a stale package index
@@ -0,0 +1,15 @@
1
+ ---
2
+ type: lint-rule
3
+ title: DKRS002
4
+ description: Per-kind Dockerfile fields written in a different order
5
+ id: DKRS002
6
+ severity: warning
7
+ category: correctness
8
+ lexicon: docker
9
+ docs: https://intentius.io/chant/lexicons/docker/rules/
10
+ ---
11
+ Per-kind Dockerfile fields written in a different order
12
+
13
+ ## Applies to
14
+
15
+ - [Dockerfile](/types/Dockerfile.md)
@@ -10,8 +10,10 @@ A config definition in Docker Compose
10
10
 
11
11
  ## Properties
12
12
 
13
- - `file` (`string`): Path to the config file
14
- - `content` (`string`): Inline config content
15
- - `external` (`boolean`): Whether the config is external
16
- - `labels` (`Record<string, string>`): Config labels
17
- - `name` (`string`): Custom config name
13
+ - `name` (`ComposeString`): Custom name for this config.
14
+ - `content` (`ComposeString`): Inline content of the config.
15
+ - `environment` (`ComposeString`): Name of an environment variable from which to get the config value.
16
+ - `file` (`ComposeString`): Path to a file containing the config value.
17
+ - `external` (`boolean | ComposeString | { name?: ComposeString }`): Specifies that this config already exists and was created outside of Compose.
18
+ - `labels` (`Record<string, ComposeString | number | boolean | null> | Array<ComposeString>`): Add metadata to the config using labels.
19
+ - `template_driver` (`ComposeString`): Driver to use for templating the config's value.
@@ -10,7 +10,11 @@ A secret definition in Docker Compose
10
10
 
11
11
  ## Properties
12
12
 
13
- - `file` (`string`): Path to the secret file
14
- - `external` (`boolean`): Whether the secret is external
15
- - `labels` (`Record<string, string>`): Secret labels
16
- - `name` (`string`): Custom secret name
13
+ - `name` (`ComposeString`): Custom name for this secret.
14
+ - `environment` (`ComposeString`): Name of an environment variable from which to get the secret value.
15
+ - `file` (`ComposeString`): Path to a file containing the secret value.
16
+ - `external` (`boolean | ComposeString | { name?: ComposeString }`): Specifies that this secret already exists and was created outside of Compose.
17
+ - `labels` (`Record<string, ComposeString | number | boolean | null> | Array<ComposeString>`): Add metadata to the secret using labels.
18
+ - `driver` (`ComposeString`): Specify which secret driver should be used for this secret.
19
+ - `driver_opts` (`Record<string, ComposeString | number>`): Specify driver-specific options.
20
+ - `template_driver` (`ComposeString`): Driver to use for templating the secret's value.
@@ -24,7 +24,10 @@ A Dockerfile definition with ordered build instructions
24
24
  - `entrypoint`: Set the entrypoint executable
25
25
  - `cmd`: Default command arguments
26
26
  - `healthcheck`: Health check instruction
27
+ - `globalArgs`: ARG instructions written before the first FROM
28
+ - `steps`: Instructions after FROM, written in the order given; one instruction per step
27
29
 
28
30
  ## Governed by
29
31
 
30
- - [DKRD012](/rules/DKRD012.md): Dockerfile has no USER instruction — container runs as root
32
+ - [DKRD012](/rules/DKRD012.md): Dockerfile's final stage has no USER instruction, or ends on USER root — container runs as root
33
+ - [DKRS002](/rules/DKRS002.md): Per-kind Dockerfile fields written in a different order
@@ -10,9 +10,13 @@ A network definition in Docker Compose
10
10
 
11
11
  ## Properties
12
12
 
13
- - `driver` (`string`): Network driver
14
- - `driver_opts` (`Record<string, string>`): Driver options
15
- - `external` (`boolean`): Whether the network is external
16
- - `labels` (`Record<string, string>`): Network labels
17
- - `internal` (`boolean`): Restrict external access
18
- - `ipam` (`object`): IP address management
13
+ - `name` (`ComposeString`): Custom name for this network.
14
+ - `driver` (`ComposeString`): Specify which driver should be used for this network. Default is 'bridge'.
15
+ - `driver_opts` (`Record<string, ComposeString | number>`): Specify driver-specific options defined as key/value pairs.
16
+ - `ipam` (`{ driver?: ComposeString; config?: Array<{ subnet?: ComposeString; ip_range?: ComposeString; gateway?: ComposeString; aux_addresses?: Record<string, ComposeString>; [key: `x-${string}`]: unknown }>; options?: Record<string, ComposeString>; [key: `x-${string}`]: unknown }`): Custom IP Address Management configuration for this network.
17
+ - `external` (`boolean | ComposeString | { name?: ComposeString; [key: `x-${string}`]: unknown }`): Specifies that this network already exists and was created outside of Compose.
18
+ - `internal` (`boolean | ComposeString`): Create an externally isolated network.
19
+ - `enable_ipv4` (`boolean | ComposeString`): Enable IPv4 networking.
20
+ - `enable_ipv6` (`boolean | ComposeString`): Enable IPv6 networking.
21
+ - `attachable` (`boolean | ComposeString`): If true, standalone containers can attach to this network.
22
+ - `labels` (`Record<string, ComposeString | number | boolean | null> | Array<ComposeString>`): Add metadata to the network using labels.
@@ -10,21 +10,99 @@ A containerized service definition in Docker Compose
10
10
 
11
11
  ## Properties
12
12
 
13
- - `image` (`string`): Container image to use
14
- - `build` (`object`): Build configuration
15
- - `command` (`string | string[]`): Override the default command
16
- - `entrypoint` (`string | string[]`): Override the default entrypoint
17
- - `environment` (`Record<string, string>`): Environment variables
18
- - `ports` (`string[]`): Published ports
19
- - `volumes` (`string[]`): Volume mounts
20
- - `networks` (`string[]`): Networks to attach
21
- - `depends_on` (`string[] | Record<string, { condition: "service_started" | "service_healthy" | "service_completed_successfully"; restart?: boolean; required?: boolean }>`): Service dependencies (short list-form, or long form with a wait condition)
22
- - `restart` (`string`): Restart policy
23
- - `labels` (`Record<string, string>`): Container labels
24
- - `healthcheck` (`object`): Health check configuration
25
- - `deploy` (`object`): Swarm deployment configuration
26
- - `secrets` (`string[]`): Secrets to expose
27
- - `configs` (`Array<string | { source: string | Declarable; target?: string; uid?: string; gid?: string; mode?: number }>`): Configs to expose (short form, or long form with a mount target)
13
+ - `develop` (`{ watch?: Array<{ ignore?: ComposeString | Array<ComposeString>; include?: ComposeString | Array<ComposeString>; path: ComposeString; action: "rebuild" | "sync" | "restart" | "sync+restart" | "sync+exec"; target?: ComposeString; exec?: { command: null | ComposeString | Array<ComposeString>; user?: ComposeString; privileged?: boolean | ComposeString; working_dir?: ComposeString; environment?: Record<string, ComposeString | number | boolean | null> | Array<ComposeString>; [key: `x-${string}`]: unknown }; initial_sync?: boolean; [key: `x-${string}`]: unknown }>; [key: `x-${string}`]: unknown } | null`)
14
+ - `deploy` (`{ mode?: ComposeString; endpoint_mode?: ComposeString; replicas?: number | ComposeString; labels?: Record<string, ComposeString | number | boolean | null> | Array<ComposeString>; rollback_config?: { parallelism?: number | ComposeString; delay?: ComposeString; failure_action?: ComposeString; monitor?: ComposeString; max_failure_ratio?: number | ComposeString; order?: "start-first" | "stop-first"; [key: `x-${string}`]: unknown }; update_config?: { parallelism?: number | ComposeString; delay?: ComposeString; failure_action?: ComposeString; monitor?: ComposeString; max_failure_ratio?: number | ComposeString; order?: "start-first" | "stop-first"; [key: `x-${string}`]: unknown }; resources?: { limits?: { cpus?: number | ComposeString; memory?: ComposeString; pids?: number | ComposeString; [key: `x-${string}`]: unknown }; reservations?: { cpus?: number | ComposeString; memory?: ComposeString; generic_resources?: Array<{ discrete_resource_spec?: { kind?: ComposeString; value?: number | ComposeString; [key: `x-${string}`]: unknown }; [key: `x-${string}`]: unknown }>; devices?: Array<{ capabilities: Array<ComposeString>; count?: ComposeString | number; device_ids?: Array<ComposeString>; driver?: ComposeString; options?: Record<string, ComposeString | number | boolean | null> | Array<ComposeString>; [key: `x-${string}`]: unknown }>; [key: `x-${string}`]: unknown }; [key: `x-${string}`]: unknown }; restart_policy?: { condition?: ComposeString; delay?: ComposeString; max_attempts?: number | ComposeString; window?: ComposeString; [key: `x-${string}`]: unknown }; placement?: { constraints?: Array<ComposeString>; preferences?: Array<{ spread?: ComposeString; [key: `x-${string}`]: unknown }>; max_replicas_per_node?: number | ComposeString; [key: `x-${string}`]: unknown }; [key: `x-${string}`]: unknown } | null`)
15
+ - `annotations` (`Record<string, ComposeString | number | boolean | null> | Array<ComposeString>`)
16
+ - `attach` (`boolean | ComposeString`)
17
+ - `build` (`ComposeString | { context?: ComposeString; dockerfile?: ComposeString; dockerfile_inline?: ComposeString; entitlements?: Array<ComposeString>; args?: Record<string, ComposeString | number | boolean | null> | Array<ComposeString>; ssh?: Record<string, ComposeString | number | boolean | null> | Array<ComposeString>; labels?: Record<string, ComposeString | number | boolean | null> | Array<ComposeString>; cache_from?: Array<ComposeString>; cache_to?: Array<ComposeString>; no_cache?: boolean | ComposeString; no_cache_filter?: ComposeString | Array<ComposeString>; additional_contexts?: Record<string, ComposeString | number | boolean | null> | Array<ComposeString>; network?: ComposeString; provenance?: ComposeString | boolean; sbom?: ComposeString | boolean; pull?: boolean | ComposeString; target?: ComposeString; shm_size?: number | ComposeString; extra_hosts?: Record<string, ComposeString | Array<ComposeString>> | Array<ComposeString>; isolation?: ComposeString; privileged?: boolean | ComposeString; secrets?: Array<ComposeString | { source?: ComposeString; target?: ComposeString; uid?: ComposeString; gid?: ComposeString; mode?: number | ComposeString; [key: `x-${string}`]: unknown }>; tags?: Array<ComposeString>; ulimits?: Record<string, number | ComposeString | { hard: number | ComposeString; soft: number | ComposeString; [key: `x-${string}`]: unknown }>; platforms?: Array<ComposeString>; [key: `x-${string}`]: unknown }`): Configuration options for building the service's image.
18
+ - `blkio_config` (`{ device_read_bps?: Array<{ path?: ComposeString; rate?: number | ComposeString }>; device_read_iops?: Array<{ path?: ComposeString; rate?: number | ComposeString }>; device_write_bps?: Array<{ path?: ComposeString; rate?: number | ComposeString }>; device_write_iops?: Array<{ path?: ComposeString; rate?: number | ComposeString }>; weight?: number | ComposeString; weight_device?: Array<{ path?: ComposeString; weight?: number | ComposeString }> }`): Block IO configuration for the service.
19
+ - `cap_add` (`Array<ComposeString>`): Add Linux capabilities. For example, 'CAP_SYS_ADMIN', 'SYS_ADMIN', or 'NET_ADMIN'.
20
+ - `cap_drop` (`Array<ComposeString>`): Drop Linux capabilities. For example, 'CAP_SYS_ADMIN', 'SYS_ADMIN', or 'NET_ADMIN'.
21
+ - `cgroup` (`"host" | "private"`): Specify the cgroup namespace to join. Use 'host' to use the host's cgroup namespace, or 'private' to use a private cgroup namespace.
22
+ - `cgroup_parent` (`ComposeString`): Specify an optional parent cgroup for the container.
23
+ - `command` (`null | ComposeString | Array<ComposeString>`): Override the default command declared by the container image, for example 'CMD' in Dockerfile.
24
+ - `configs` (`Array<ComposeString | { source?: ComposeString; target?: ComposeString; uid?: ComposeString; gid?: ComposeString; mode?: number | ComposeString; [key: `x-${string}`]: unknown }>`): Grant access to Configs on a per-service basis.
25
+ - `container_name` (`ComposeString`): Specify a custom container name, rather than a generated default name.
26
+ - `cpu_count` (`ComposeString | number`): Number of usable CPUs.
27
+ - `cpu_percent` (`ComposeString | number`): Percentage of CPU resources to use.
28
+ - `cpu_shares` (`number | ComposeString`): CPU shares (relative weight) for the container.
29
+ - `cpu_quota` (`number | ComposeString`): Limit the CPU CFS (Completely Fair Scheduler) quota.
30
+ - `cpu_period` (`number | ComposeString`): Limit the CPU CFS (Completely Fair Scheduler) period.
31
+ - `cpu_rt_period` (`number | ComposeString`): Limit the CPU real-time period in microseconds or a duration.
32
+ - `cpu_rt_runtime` (`number | ComposeString`): Limit the CPU real-time runtime in microseconds or a duration.
33
+ - `cpus` (`number | ComposeString`): Number of CPUs to use. A floating-point value is supported to request partial CPUs.
34
+ - `cpuset` (`ComposeString`): CPUs in which to allow execution (0-3, 0,1).
35
+ - `credential_spec` (`{ config?: ComposeString; file?: ComposeString; registry?: ComposeString; [key: `x-${string}`]: unknown }`): Configure the credential spec for managed service account.
36
+ - `depends_on` (`Array<ComposeString> | Record<string, { restart?: boolean | ComposeString; required?: boolean; condition: "service_started" | "service_healthy" | "service_completed_successfully"; [key: `x-${string}`]: unknown }>`): Express dependency between services. Service dependencies cause services to be started in dependency order. The dependent service will wait for the dependency to be ready before starting.
37
+ - `device_cgroup_rules` (`Array<ComposeString>`): Add rules to the cgroup allowed devices list.
38
+ - `devices` (`Array<ComposeString | { source: ComposeString; target?: ComposeString; permissions?: ComposeString; [key: `x-${string}`]: unknown }>`): List of device mappings for the container.
39
+ - `dns` (`ComposeString | Array<ComposeString>`): Custom DNS servers to set for the service container.
40
+ - `dns_opt` (`Array<ComposeString>`): Custom DNS options to be passed to the container's DNS resolver.
41
+ - `dns_search` (`ComposeString | Array<ComposeString>`): Custom DNS search domains to set on the service container.
42
+ - `domainname` (`ComposeString`): Custom domain name to use for the service container.
43
+ - `entrypoint` (`null | ComposeString | Array<ComposeString>`): Override the default entrypoint declared by the container image, for example 'ENTRYPOINT' in Dockerfile.
44
+ - `env_file` (`ComposeString | Array<ComposeString | { path: ComposeString; format?: ComposeString; required?: boolean | ComposeString }>`): Add environment variables from a file or multiple files. Can be a single file path or a list of file paths.
45
+ - `label_file` (`ComposeString | Array<ComposeString>`): Add metadata to containers using files containing Docker labels.
46
+ - `environment` (`Record<string, ComposeString | number | boolean | null> | Array<ComposeString>`): Add environment variables. You can use either an array or a list of KEY=VAL pairs.
47
+ - `expose` (`Array<ComposeString | number>`): Expose ports without publishing them to the host machine - they'll only be accessible to linked services.
48
+ - `extends` (`ComposeString | { service: ComposeString; file?: ComposeString }`): Extend another service, in the current file or another file.
49
+ - `provider` (`{ type: ComposeString; options?: Record<string, ComposeString | number | boolean | Array<ComposeString | number | boolean>>; [key: `x-${string}`]: unknown }`): Specify a service which will not be manage by Compose directly, and delegate its management to an external provider.
50
+ - `external_links` (`Array<ComposeString>`): Link to services started outside this Compose application. Specify services as <service_name>:<alias>.
51
+ - `extra_hosts` (`Record<string, ComposeString | Array<ComposeString>> | Array<ComposeString>`): Add hostname mappings to the container network interface configuration.
52
+ - `gpus` (`"all" | Array<{ capabilities?: Array<ComposeString>; count?: ComposeString | number; device_ids?: Array<ComposeString>; driver?: ComposeString; options?: Record<string, ComposeString | number | boolean | null> | Array<ComposeString> }>`): Define GPU devices to use. Can be set to 'all' to use all GPUs, or a list of specific GPU devices.
53
+ - `group_add` (`Array<ComposeString | number>`): Add additional groups which user inside the container should be member of.
54
+ - `healthcheck` (`{ disable?: boolean | ComposeString; interval?: ComposeString; retries?: number | ComposeString; test?: ComposeString | Array<ComposeString>; timeout?: ComposeString; start_period?: ComposeString; start_interval?: ComposeString; [key: `x-${string}`]: unknown }`): Configure a health check for the container to monitor its health status.
55
+ - `hostname` (`ComposeString`): Define a custom hostname for the service container.
56
+ - `image` (`ComposeString`): Specify the image to start the container from. Can be a repository/tag, a digest, or a local image ID.
57
+ - `init` (`boolean | ComposeString`): Run as an init process inside the container that forwards signals and reaps processes.
58
+ - `ipc` (`ComposeString`): IPC sharing mode for the service container. Use 'host' to share the host's IPC namespace, 'service:[service_name]' to share with another service, or 'shareable' to allow other services to share this service's IPC namespace.
59
+ - `isolation` (`ComposeString`): Container isolation technology to use. Supported values are platform-specific.
60
+ - `labels` (`Record<string, ComposeString | number | boolean | null> | Array<ComposeString>`): Add metadata to containers using Docker labels. You can use either an array or a list.
61
+ - `links` (`Array<ComposeString>`): Link to containers in another service. Either specify both the service name and a link alias (SERVICE:ALIAS), or just the service name.
62
+ - `logging` (`{ driver?: ComposeString; options?: Record<string, ComposeString | number | null>; [key: `x-${string}`]: unknown }`): Logging configuration for the service.
63
+ - `mac_address` (`ComposeString`): Container MAC address to set.
64
+ - `mem_limit` (`number | ComposeString`): Memory limit for the container. A string value can use suffix like '2g' for 2 gigabytes.
65
+ - `mem_reservation` (`ComposeString | number`): Memory reservation for the container.
66
+ - `mem_swappiness` (`number | ComposeString`): Container memory swappiness as percentage (0 to 100).
67
+ - `memswap_limit` (`number | ComposeString`): Amount of memory the container is allowed to swap to disk. Set to -1 to enable unlimited swap.
68
+ - `network_mode` (`ComposeString`): Network mode. Values can be 'bridge', 'host', 'none', 'service:[service name]', or 'container:[container name]'.
69
+ - `models` (`Array<ComposeString> | Record<string, { endpoint_var?: ComposeString; model_var?: ComposeString; [key: `x-${string}`]: unknown } | null>`): AI Models to use, referencing entries under the top-level models key.
70
+ - `networks` (`Array<ComposeString> | Record<string, { aliases?: Array<ComposeString>; interface_name?: ComposeString; ipv4_address?: ComposeString; ipv6_address?: ComposeString; link_local_ips?: Array<ComposeString>; mac_address?: ComposeString; driver_opts?: Record<string, ComposeString | number>; priority?: number; gw_priority?: number; [key: `x-${string}`]: unknown } | null>`): Networks to join, referencing entries under the top-level networks key. Can be a list of network names or a mapping of network name to network configuration.
71
+ - `oom_kill_disable` (`boolean | ComposeString`): Disable OOM Killer for the container.
72
+ - `oom_score_adj` (`ComposeString | number`): Tune host's OOM preferences for the container (accepts -1000 to 1000).
73
+ - `pid` (`ComposeString | null`): PID mode for container.
74
+ - `pids_limit` (`number | ComposeString`): Tune a container's PIDs limit. Set to -1 for unlimited PIDs.
75
+ - `platform` (`ComposeString`): Target platform to run on, e.g., 'linux/amd64', 'linux/arm64', or 'windows/amd64'.
76
+ - `ports` (`Array<number | ComposeString | { name?: ComposeString; mode?: ComposeString; host_ip?: ComposeString; target?: number | ComposeString; published?: ComposeString | number; protocol?: ComposeString; app_protocol?: ComposeString; [key: `x-${string}`]: unknown }>`): Expose container ports. Short format ([HOST:]CONTAINER[/PROTOCOL]).
77
+ - `pre_start` (`Array<{ command?: null | ComposeString | Array<ComposeString>; image?: ComposeString; user?: ComposeString; privileged?: boolean | ComposeString; working_dir?: ComposeString; environment?: Record<string, ComposeString | number | boolean | null> | Array<ComposeString>; per_replica?: boolean | ComposeString; [key: `x-${string}`]: unknown }>`): Init containers to run to completion before the service container is started. Each step runs in its own ephemeral container, in declared order; a non-zero exit fails the bring-up of the service and its dependents.
78
+ - `post_start` (`Array<{ command: null | ComposeString | Array<ComposeString>; user?: ComposeString; privileged?: boolean | ComposeString; working_dir?: ComposeString; environment?: Record<string, ComposeString | number | boolean | null> | Array<ComposeString>; [key: `x-${string}`]: unknown }>`): Commands to run after the container starts. If any command fails, the container stops.
79
+ - `pre_stop` (`Array<{ command: null | ComposeString | Array<ComposeString>; user?: ComposeString; privileged?: boolean | ComposeString; working_dir?: ComposeString; environment?: Record<string, ComposeString | number | boolean | null> | Array<ComposeString>; [key: `x-${string}`]: unknown }>`): Commands to run before the container stops. If any command fails, the container stop is aborted.
80
+ - `privileged` (`boolean | ComposeString`): Give extended privileges to the service container.
81
+ - `profiles` (`Array<ComposeString>`): List of profiles for this service. When profiles are specified, services are only started when the profile is activated.
82
+ - `pull_policy` (`ComposeString`): Policy for pulling images. Options include: 'always', 'never', 'if_not_present', 'missing', 'build', or time-based refresh policies.
83
+ - `pull_refresh_after` (`ComposeString`): Time after which to refresh the image. Used with pull_policy=refresh.
84
+ - `read_only` (`boolean | ComposeString`): Mount the container's filesystem as read only.
85
+ - `restart` (`ComposeString`): Restart policy for the service container. Options include: 'no', 'always', 'on-failure', and 'unless-stopped'.
86
+ - `runtime` (`ComposeString`): Runtime to use for this container, e.g., 'runc'.
87
+ - `scale` (`number | ComposeString`): Number of containers to deploy for this service.
88
+ - `security_opt` (`Array<ComposeString>`): Override the default labeling scheme for each container.
89
+ - `shm_size` (`number | ComposeString`): Size of /dev/shm. A string value can use suffix like '2g' for 2 gigabytes.
90
+ - `secrets` (`Array<ComposeString | { source?: ComposeString; target?: ComposeString; uid?: ComposeString; gid?: ComposeString; mode?: number | ComposeString; [key: `x-${string}`]: unknown }>`): Grant access to Secrets on a per-service basis.
91
+ - `sysctls` (`Record<string, ComposeString | number | boolean | null> | Array<ComposeString>`): Kernel parameters to set in the container. You can use either an array or a list.
92
+ - `stdin_open` (`boolean | ComposeString`): Keep STDIN open even if not attached.
93
+ - `stop_grace_period` (`ComposeString`): Time to wait for the container to stop gracefully before sending SIGKILL (e.g., '1s', '1m30s').
94
+ - `stop_signal` (`ComposeString`): Signal to stop the container (e.g., 'SIGTERM', 'SIGINT').
95
+ - `storage_opt` (`Record<string, unknown>`): Storage driver options for the container.
96
+ - `tmpfs` (`ComposeString | Array<ComposeString>`): Mount a temporary filesystem (tmpfs) into the container. Can be a single value or a list.
97
+ - `tty` (`boolean | ComposeString`): Allocate a pseudo-TTY to service container.
98
+ - `ulimits` (`Record<string, number | ComposeString | { hard: number | ComposeString; soft: number | ComposeString; [key: `x-${string}`]: unknown }>`): Override the default ulimits for a container.
99
+ - `use_api_socket` (`boolean`): Bind mount Docker API socket and required auth.
100
+ - `user` (`ComposeString`): Username or UID to run the container process as.
101
+ - `uts` (`ComposeString`): UTS namespace to use. 'host' shares the host's UTS namespace.
102
+ - `userns_mode` (`ComposeString`): User namespace to use. 'host' shares the host's user namespace.
103
+ - `volumes` (`Array<ComposeString | { type: "bind" | "volume" | "tmpfs" | "cluster" | "npipe" | "image"; source?: ComposeString; target?: ComposeString; read_only?: boolean | ComposeString; consistency?: ComposeString; bind?: { propagation?: ComposeString; create_host_path?: boolean | ComposeString; recursive?: "enabled" | "disabled" | "writable" | "readonly"; selinux?: "z" | "Z"; [key: `x-${string}`]: unknown }; volume?: { labels?: Record<string, ComposeString | number | boolean | null> | Array<ComposeString>; nocopy?: boolean | ComposeString; subpath?: ComposeString; [key: `x-${string}`]: unknown }; tmpfs?: { size?: number | ComposeString; mode?: number | ComposeString; [key: `x-${string}`]: unknown }; image?: { subpath?: ComposeString; [key: `x-${string}`]: unknown }; [key: `x-${string}`]: unknown }>`): Mount host paths or named volumes accessible to the container. Short syntax (VOLUME:CONTAINER_PATH[:MODE])
104
+ - `volumes_from` (`Array<ComposeString>`): Mount volumes from another service or container. Optionally specify read-only access (ro) or read-write (rw).
105
+ - `working_dir` (`ComposeString`): The working directory in which the entrypoint or command will be run
28
106
 
29
107
  ## Governed by
30
108
 
@@ -10,11 +10,11 @@ A named volume definition in Docker Compose
10
10
 
11
11
  ## Properties
12
12
 
13
- - `driver` (`string`): Volume driver
14
- - `driver_opts` (`Record<string, string>`): Driver options
15
- - `external` (`boolean`): Whether the volume is external
16
- - `labels` (`Record<string, string>`): Volume labels
17
- - `name` (`string`): Custom volume name
13
+ - `name` (`ComposeString`): Custom name for this volume.
14
+ - `driver` (`ComposeString`): Specify which volume driver should be used for this volume.
15
+ - `driver_opts` (`Record<string, ComposeString | number>`): Specify driver-specific options.
16
+ - `external` (`boolean | ComposeString | { name?: ComposeString; [key: `x-${string}`]: unknown }`): Specifies that this volume already exists and was created outside of Compose.
17
+ - `labels` (`Record<string, ComposeString | number | boolean | null> | Array<ComposeString>`): Add metadata to the volume using labels.
18
18
 
19
19
  ## Governed by
20
20
 
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAiC,MAAM,0BAA0B,CAAC;AAc7F,eAAO,MAAM,YAAY,EAAE,aA8O1B,CAAC"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAiC,MAAM,0BAA0B,CAAC;AAe7F,eAAO,MAAM,YAAY,EAAE,aA8O1B,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * DKRD019: ADD of a remote URL without --checksum
3
+ *
4
+ * ADD fetches an http(s) URL at build time and trusts whatever comes back.
5
+ * `ADD --checksum=sha256:...` makes the build fail when the content changes.
6
+ */
7
+
8
+ import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
9
+ import { eachDockerfile, stageLabel } from "./docker-helpers";
10
+
11
+ export const dkrd019: PostSynthCheck = {
12
+ id: "DKRD019",
13
+ description: "ADD fetches a remote URL without --checksum",
14
+
15
+ check(ctx: PostSynthContext): PostSynthDiagnostic[] {
16
+ const diagnostics: PostSynthDiagnostic[] = [];
17
+
18
+ for (const { fileName, parsed } of eachDockerfile(ctx.outputs)) {
19
+ for (const stage of parsed.stages) {
20
+ for (const instr of stage.instructions) {
21
+ if (instr.instruction !== "ADD") continue;
22
+ const words = instr.value.split(/\s+/);
23
+ if (words.some((w) => w.startsWith("--checksum="))) continue;
24
+ const url = words.find((w) => /^https?:\/\//i.test(w));
25
+ if (!url) continue;
26
+ diagnostics.push({
27
+ checkId: "DKRD019",
28
+ severity: "warning",
29
+ message: `${fileName} ${stageLabel(stage)}: ADD ${url} has no --checksum, so the build accepts whatever the URL serves. Add --checksum=sha256:<digest>.`,
30
+ lexicon: "docker",
31
+ });
32
+ }
33
+ }
34
+ }
35
+
36
+ return diagnostics;
37
+ },
38
+ };
@@ -0,0 +1,39 @@
1
+ /**
2
+ * DKRD020: apt-get update in its own RUN
3
+ *
4
+ * A RUN that only runs `apt-get update` is cached as its own layer, so a
5
+ * later `apt-get install` in another RUN can install from a stale package
6
+ * index. Update and install in the same RUN.
7
+ */
8
+
9
+ import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
10
+ import { commandText, eachDockerfile, stageLabel } from "./docker-helpers";
11
+
12
+ const UPDATE = /\bapt(-get)?\s+update\b/;
13
+ const INSTALL = /\bapt(-get)?\s+(install|upgrade|dist-upgrade)\b/;
14
+
15
+ export const dkrd020: PostSynthCheck = {
16
+ id: "DKRD020",
17
+ description: "apt-get update in a different RUN from apt-get install — the install can use a stale package index",
18
+
19
+ check(ctx: PostSynthContext): PostSynthDiagnostic[] {
20
+ const diagnostics: PostSynthDiagnostic[] = [];
21
+
22
+ for (const { fileName, parsed } of eachDockerfile(ctx.outputs)) {
23
+ for (const stage of parsed.stages) {
24
+ const runs = stage.instructions.filter((i) => i.instruction === "RUN");
25
+ const updateAt = runs.findIndex((r) => UPDATE.test(commandText(r)) && !INSTALL.test(commandText(r)));
26
+ if (updateAt === -1) continue;
27
+ if (!runs.slice(updateAt + 1).some((r) => INSTALL.test(commandText(r)))) continue;
28
+ diagnostics.push({
29
+ checkId: "DKRD020",
30
+ severity: "warning",
31
+ message: `${fileName} ${stageLabel(stage)}: apt-get update runs in its own RUN, and a later RUN installs from that cached index. Run update and install in one RUN: apt-get update && apt-get install -y --no-install-recommends ...`,
32
+ lexicon: "docker",
33
+ });
34
+ }
35
+ }
36
+
37
+ return diagnostics;
38
+ },
39
+ };
@@ -0,0 +1,65 @@
1
+ /**
2
+ * DKRD013: Whole build context copied before installing dependencies
3
+ *
4
+ * `COPY . .` followed by a dependency install (npm ci, pip install -r,
5
+ * go mod download, ...) in the same stage invalidates the install layer on
6
+ * every source change. Copy the dependency manifests first, install, then
7
+ * copy the rest.
8
+ */
9
+
10
+ import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
11
+ import { commandText, eachDockerfile, instrText, stageLabel } from "./docker-helpers";
12
+
13
+ /** Installs whose inputs are a few manifest files rather than the whole source tree. */
14
+ const INSTALL = [
15
+ /\bnpm\s+(ci|install|i)(\s+--?[\w-]+(=\S+)?)*\s*($|&&|;|\|)/m,
16
+ /\byarn(\s+install)?(\s+--[\w-]+)*\s*($|&&|;|\|)/m,
17
+ /\bpnpm\s+(install|i)\b/,
18
+ /\bbun\s+install\b/,
19
+ /\bpip3?\s+install\b[^&;|]*\s-r\s/,
20
+ /\bpoetry\s+install\b/,
21
+ /\buv\s+sync\b/,
22
+ /\bpipenv\s+install\b/,
23
+ /\bgo\s+mod\s+download\b/,
24
+ /\bbundle\s+install\b/,
25
+ /\bcomposer\s+install\b/,
26
+ // A string, not a regex literal: the egress scan reads a bare `fetch` in code as a call.
27
+ new RegExp("\\bcargo\\s+fetch\\b"),
28
+ /\bdotnet\s+restore\b/,
29
+ /\bmvn\b[^&;|]*\bdependency:go-offline\b/,
30
+ ];
31
+
32
+ /** `COPY . <dest>` (or `./`) from the build context, not from another stage. */
33
+ function copiesWholeContext(value: string): boolean {
34
+ const words = value.split(/\s+/).filter((w) => w.length > 0);
35
+ if (words.some((w) => w.startsWith("--from"))) return false;
36
+ const args = words.filter((w) => !w.startsWith("--"));
37
+ if (args[0]?.startsWith("[")) return false;
38
+ return args.slice(0, -1).some((src) => src === "." || src === "./");
39
+ }
40
+
41
+ export const dkrd013: PostSynthCheck = {
42
+ id: "DKRD013",
43
+ description: "Whole build context copied before a dependency install — every source change re-runs the install",
44
+
45
+ check(ctx: PostSynthContext): PostSynthDiagnostic[] {
46
+ const diagnostics: PostSynthDiagnostic[] = [];
47
+
48
+ for (const { fileName, parsed } of eachDockerfile(ctx.outputs)) {
49
+ for (const stage of parsed.stages) {
50
+ const copyAt = stage.instructions.findIndex((i) => i.instruction === "COPY" && copiesWholeContext(i.value));
51
+ if (copyAt === -1) continue;
52
+ const install = stage.instructions.slice(copyAt + 1).find((i) => i.instruction === "RUN" && INSTALL.some((re) => re.test(commandText(i))));
53
+ if (!install) continue;
54
+ diagnostics.push({
55
+ checkId: "DKRD013",
56
+ severity: "warning",
57
+ message: `${fileName} ${stageLabel(stage)}: ${instrText(stage.instructions[copyAt]!)} comes before ${instrText(install)}, so any source change re-runs the install. Copy the dependency manifests first, run the install, then copy the rest.`,
58
+ lexicon: "docker",
59
+ });
60
+ }
61
+ }
62
+
63
+ return diagnostics;
64
+ },
65
+ };
@@ -0,0 +1,54 @@
1
+ /**
2
+ * DKRD016: COPY --from names no earlier stage
3
+ *
4
+ * `COPY --from=<name>` reads from an earlier stage with that name (or
5
+ * index). A name that only a later stage has, or that no stage has, is
6
+ * pulled as an image instead, which is almost never what was meant.
7
+ */
8
+
9
+ import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
10
+ import { eachDockerfile, stageLabel } from "./docker-helpers";
11
+
12
+ /** Looks like an image reference rather than a stage name: has a tag, digest or registry path. */
13
+ function looksLikeImage(ref: string): boolean {
14
+ return /[:/@]/.test(ref);
15
+ }
16
+
17
+ export const dkrd016: PostSynthCheck = {
18
+ id: "DKRD016",
19
+ description: "COPY --from names a stage that is not defined before it",
20
+
21
+ check(ctx: PostSynthContext): PostSynthDiagnostic[] {
22
+ const diagnostics: PostSynthDiagnostic[] = [];
23
+
24
+ for (const { fileName, parsed } of eachDockerfile(ctx.outputs)) {
25
+ for (const stage of parsed.stages) {
26
+ for (const instr of stage.instructions) {
27
+ if (instr.instruction !== "COPY" && instr.instruction !== "ADD") continue;
28
+ const m = instr.value.match(/--from=(\S+)/);
29
+ if (!m) continue;
30
+ const ref = m[1]!;
31
+ if (ref.includes("$")) continue;
32
+ const earlier = parsed.stages.slice(0, stage.index);
33
+ if (/^\d+$/.test(ref)) {
34
+ if (Number(ref) < stage.index) continue;
35
+ } else if (earlier.some((s) => s.as?.toLowerCase() === ref.toLowerCase())) {
36
+ continue;
37
+ }
38
+ const later = parsed.stages.slice(stage.index).find((s) => s.as?.toLowerCase() === ref.toLowerCase() || String(s.index) === ref);
39
+ if (!later && looksLikeImage(ref)) continue;
40
+ diagnostics.push({
41
+ checkId: "DKRD016",
42
+ severity: "warning",
43
+ message: later
44
+ ? `${fileName} ${stageLabel(stage)}: ${instr.instruction} --from=${ref} names ${stageLabel(later)}, which is not defined until later. Move that stage before this one.`
45
+ : `${fileName} ${stageLabel(stage)}: ${instr.instruction} --from=${ref} names no stage, so Docker pulls an image called "${ref}". Name an earlier stage, or give the image a tag.`,
46
+ lexicon: "docker",
47
+ });
48
+ }
49
+ }
50
+ }
51
+
52
+ return diagnostics;
53
+ },
54
+ };