microvms-core 1.1.1

The MicroVMs control-plane and in-VM client: every trap closure, the cost engine, the sizing model
Documentation
# SPDX-License-Identifier: Apache-2.0
#
# The behavior spec for IMAGE-1 through IMAGE-4 in verify/spec/core.symspec.json (issue #220):
# wrapping a task Dockerfile with the agentd stanza, and deriving the base image that pairs
# with it. `crates/model/src/wrap.rs` checks the same requirements as a Stateright model, and the
# bolero harness in `crates/microvms-core/tests/wrap_fuzz.rs` fuzzes `wrap_dockerfile` over
# arbitrary Dockerfile text. Each scenario's tags name the requirements it verifies.
#
# Run by `crates/microvms-core/tests/bdd_wrap.rs` against the real functions, with no AWS call:
# the create preflight is the one `ControlPlane::create_image` runs before the wire.

Feature: A task Dockerfile becomes a buildable one with one call

  Rule: IMAGE-1 — the wrapped stanza and the default Dockerfile's are one text

    @IMAGE-1
    Scenario: a bare FROM wraps to the default Dockerfile
      Given the task Dockerfile "FROM x"
      When the task Dockerfile is wrapped
      Then the result is the default Dockerfile for base "x" with no workdir

    @IMAGE-1
    Scenario: a workdir option writes the default generator's workdir lines
      Given the task Dockerfile "FROM x"
      And the wrap option workdir "/srv/task"
      When the task Dockerfile is wrapped
      Then the result is the default Dockerfile for base "x" with workdir "/srv/task"

  Rule: IMAGE-2 — the result ends with the bootstrap invariant, whatever the task set

    @IMAGE-2
    Scenario: the task's own entrypoint and command are overridden
      Given the task Dockerfile:
        """
        FROM python:3.12-slim
        WORKDIR /app
        ENV AGENTD_PORT=8080
        ENTRYPOINT ["/bin/sh", "-c"]
        CMD ["python", "serve.py"]
        """
      When the task Dockerfile is wrapped
      Then the wrap succeeds
      And the result ends with the lines:
        """
        ENV AGENTD_PORT=9000
        ENV AGENTD_LOG=info
        EXPOSE 9000
        ENTRYPOINT []
        CMD ["/agentd"]
        """
      And the create preflight accepts the result under the from-Dockerfile base

    @IMAGE-2
    Scenario: a task that ends on another user has USER root restored before the stanza
      Given the task Dockerfile:
        """
        FROM python:3.12-slim
        RUN useradd -m app
        USER app
        """
      When the task Dockerfile is wrapped
      Then the wrap succeeds
      And "USER root" is the first line after the task text

    @IMAGE-2
    Scenario: a task that ends on root gets no extra USER line
      Given the task Dockerfile:
        """
        FROM python:3.12-slim
        USER app
        USER root
        """
      When the task Dockerfile is wrapped
      Then the wrap succeeds
      And the result adds no USER line

    @IMAGE-2
    Scenario: a task with no trailing newline is normalized before the stanza
      Given the task Dockerfile "FROM x" with no trailing newline
      When the task Dockerfile is wrapped
      Then the wrap succeeds
      And the line after the task text is "COPY agentd /agentd"

  Rule: IMAGE-3 — a task the stanza cannot be appended to safely is refused

    @IMAGE-3
    Scenario: a Dockerfile with no FROM is refused
      Given the task Dockerfile "RUN echo hello"
      When the task Dockerfile is wrapped
      Then the wrap is refused naming "no FROM"

    @IMAGE-3
    Scenario: a line continuation at the end would swallow the stanza's first line
      Given the task Dockerfile:
        """
        FROM x
        RUN apt-get update && \
        """
      When the task Dockerfile is wrapped
      Then the wrap is refused naming "line continuation"

    @IMAGE-3
    Scenario: a continuation in a custom escape character is still a continuation
      Given the task Dockerfile:
        """
        # escape=`
        FROM x
        RUN echo one `
        """
      When the task Dockerfile is wrapped
      Then the wrap is refused naming "line continuation"

    @IMAGE-3
    Scenario: an unterminated heredoc would swallow the whole stanza
      Given the task Dockerfile:
        """
        FROM x
        RUN <<EOF
        echo never closed
        """
      When the task Dockerfile is wrapped
      Then the wrap is refused naming "heredoc"

    @IMAGE-3
    Scenario: a keepalive the client cannot tolerate is refused
      Given the task Dockerfile:
        """
        FROM x
        ENV AGENTD_SSE_KEEPALIVE_SECS=90
        """
      When the task Dockerfile is wrapped
      Then the wrap is refused naming "AGENTD_SSE_KEEPALIVE_SECS=90"

    @IMAGE-3
    Scenario: a workdir option that is not one absolute path is refused
      Given the task Dockerfile "FROM x"
      And the wrap option workdir "relative/dir"
      When the task Dockerfile is wrapped
      Then the wrap is refused naming "absolute path"

    @IMAGE-3
    Scenario: inheriting a workdir nothing declares is refused
      Given the task Dockerfile "FROM x"
      And the wrap option to inherit the workdir
      When the task Dockerfile is wrapped
      Then the wrap is refused naming "nothing to inherit"

    @IMAGE-3
    Scenario: inheriting the task's own WORKDIR is accepted
      Given the task Dockerfile:
        """
        FROM x
        WORKDIR /app
        """
      And the wrap option to inherit the workdir
      When the task Dockerfile is wrapped
      Then the wrap succeeds

  Rule: IMAGE-4 — the base image comes from the Dockerfile and satisfies the FROM guard

    @IMAGE-4
    Scenario: the managed base refuses a task on another base, the derived base accepts it
      Given the task Dockerfile "FROM python:3.12-slim"
      When the task Dockerfile is wrapped
      Then the create preflight refuses the result under the managed base naming "python:3.12-slim"
      And the create preflight accepts the result under the from-Dockerfile base

    @IMAGE-4
    Scenario: a derived base keeps the managed base name and takes the first FROM
      Given the task Dockerfile:
        """
        FROM --platform=linux/arm64 golang:1.23 AS build
        FROM python:3.12-slim
        """
      When a base image is derived from the task Dockerfile
      Then the derived base's docker_ref is "golang:1.23"
      And the derived base's name is the managed base's

    @IMAGE-4
    Scenario: a digest-pinned FROM keeps its digest and passes the guard
      Given the task Dockerfile "FROM public.ecr.aws/amazonlinux/amazonlinux:2023-minimal@sha256:c439fb4994ea7ca529233d6256446d3f8b7b4efb58956073e015303a170011de"
      When the task Dockerfile is wrapped
      Then the create preflight accepts the result under the from-Dockerfile base
      And the create preflight accepts the result under the managed base

    @IMAGE-4
    Scenario: a Dockerfile with no FROM has no base to derive
      Given the task Dockerfile "RUN echo hello"
      When a base image is derived from the task Dockerfile
      Then the derivation is refused naming "no FROM"