> ## Documentation Index
> Fetch the complete documentation index at: https://docs.endorlabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Container registry scanning

> <Badge color="green">Beta</Badge> <br /> List and scan container images directly from a registry using filters and scan plans.

export const YamlTable = ({children, data: propData, content}) => {
  const KV_RE = /^([A-Za-z][A-Za-z0-9_()/#\s-]+?):\s*(.+)$/;
  const INLINE_MD_RE = /(\[([^\]]+)\]\(([^)]+)\))|(`([^`]+)`)|(\*\*([^*]+)\*\*)|(\*([^*]+)\*)/g;
  const YES_RE = /^-yes-$/i;
  const NO_RE = /^-no-$/i;
  const LIMITED_RE = /^-(limited|partial)-$/i;
  const NA_RE = /^-(na|none)-$/i;
  const NA2_RE = /^-na2-$/i;
  const SIMPLE_TAG_RE = /(<br\s*\/?>)|(<p\s*\/?>)|(-note-)|(-warning-)/gi;
  const tryParseKV = trimmed => {
    const m = KV_RE.exec(trimmed);
    return m ? {
      key: m[1],
      value: m[2].trim()
    } : null;
  };
  const registerKey = (key, seenKeys, orderedKeys) => {
    if (!seenKeys.has(key)) {
      orderedKeys.push(key);
      seenKeys.add(key);
    }
  };
  const flushEntry = (currentEntry, entries) => {
    if (Object.keys(currentEntry).length > 0) entries.push(currentEntry);
  };
  const parseDashPrefixed = (lines, entries, orderedKeys, seenKeys) => {
    let currentEntry = {};
    let inEntry = false;
    for (const line of lines) {
      const trimmed = line.trim();
      if (trimmed.startsWith('- ')) {
        if (inEntry) entries.push(currentEntry);
        currentEntry = {};
        inEntry = true;
        const kv = tryParseKV(trimmed.substring(2).trim());
        if (kv) {
          registerKey(kv.key, seenKeys, orderedKeys);
          currentEntry[kv.key] = kv.value;
        }
      } else if (inEntry && trimmed !== '') {
        const kv = tryParseKV(trimmed);
        if (kv) {
          registerKey(kv.key, seenKeys, orderedKeys);
          currentEntry[kv.key] = kv.value;
        }
      }
    }
    flushEntry(currentEntry, entries);
  };
  const parseBlankSeparated = (lines, entries, orderedKeys, seenKeys) => {
    let currentEntry = {};
    let inEntry = false;
    for (const line of lines) {
      const trimmed = line.trim();
      if (trimmed === '') {
        if (inEntry) {
          flushEntry(currentEntry, entries);
          currentEntry = {};
          inEntry = false;
        }
        continue;
      }
      const kv = tryParseKV(trimmed);
      if (!kv) continue;
      const isNewEntry = !line.startsWith(' ') && !line.startsWith('\t');
      if (isNewEntry && inEntry && Object.keys(currentEntry).length > 0) {
        entries.push(currentEntry);
        currentEntry = {};
      }
      registerKey(kv.key, seenKeys, orderedKeys);
      currentEntry[kv.key] = kv.value;
      inEntry = true;
    }
    flushEntry(currentEntry, entries);
  };
  const normalizeEntries = (entries, orderedKeys) => entries.map(entry => {
    const filled = {};
    for (const key of orderedKeys) filled[key] = entry[key] || '';
    return filled;
  });
  const parseYamlTableContent = contentStr => {
    if (!contentStr) return [];
    const entries = [];
    const orderedKeys = [];
    const seenKeys = new Set();
    const lines = contentStr.split('\n');
    if (lines.some(line => line.trim().startsWith('- '))) {
      parseDashPrefixed(lines, entries, orderedKeys, seenKeys);
    } else {
      parseBlankSeparated(lines, entries, orderedKeys, seenKeys);
    }
    return normalizeEntries(entries, orderedKeys);
  };
  const processText = text => {
    if (!text) return text;
    const parts = [];
    let keyIndex = 0;
    let lastIndex = 0;
    let match;
    while ((match = INLINE_MD_RE.exec(text)) !== null) {
      if (match.index > lastIndex) parts.push(text.slice(lastIndex, match.index));
      if (match[1]) {
        parts.push(<a key={keyIndex++} href={match[3]}>{match[2]}</a>);
      } else if (match[4]) {
        parts.push(<code key={keyIndex++}>{match[5]}</code>);
      } else if (match[6]) {
        parts.push(<strong key={keyIndex++}>{match[7]}</strong>);
      } else if (match[8]) {
        parts.push(<em key={keyIndex++}>{match[9]}</em>);
      }
      lastIndex = match.index + match[0].length;
    }
    if (lastIndex < text.length) parts.push(text.slice(lastIndex));
    if (parts.length === 0) return text;
    const keyRef = {
      current: keyIndex
    };
    return expandHtmlTags(parts, keyRef);
  };
  const processBadges = text => {
    if (!text || typeof text !== 'string') return text;
    if (YES_RE.test(text)) return <span className="yt-badge-yes" role="img" aria-label="Supported" title="Supported">✓</span>;
    if (NO_RE.test(text)) return <span className="yt-badge-no" role="img" aria-label="Not supported" title="Not supported">✗</span>;
    if (LIMITED_RE.test(text)) return <span className="yt-badge-limited" role="img" aria-label="Partially supported" title="Partially supported">◐</span>;
    if (NA_RE.test(text) || NA2_RE.test(text)) return <span className="yt-sr-only" title="Not applicable">Not applicable</span>;
    return processText(text);
  };
  const cellClassName = text => {
    if (!text || typeof text !== 'string') return undefined;
    if (NA_RE.test(text)) return 'yt-cell-na';
    if (NA2_RE.test(text)) return 'yt-cell-na2';
    return undefined;
  };
  const expandSimpleTags = (str, keyRef) => {
    const result = [];
    let last = 0;
    SIMPLE_TAG_RE.lastIndex = 0;
    let m;
    while ((m = SIMPLE_TAG_RE.exec(str)) !== null) {
      if (m.index > last) result.push(str.slice(last, m.index));
      if (m[1]) {
        result.push(<br key={keyRef.current++} />);
      } else if (m[2]) {
        result.push(<br key={keyRef.current++} />, <br key={keyRef.current++} />);
      } else if (m[3]) {
        result.push(<span key={keyRef.current++} className="yt-badge-note" style={{
          fontWeight: 600
        }}>Note: </span>);
      } else if (m[4]) {
        result.push(<span key={keyRef.current++} className="yt-badge-warning" style={{
          fontWeight: 600
        }}>Warning: </span>);
      }
      last = m.index + m[0].length;
    }
    if (last < str.length) result.push(str.slice(last));
    return result;
  };
  const expandHtmlTags = (chunks, keyRef) => {
    const out = [];
    for (const chunk of chunks) {
      if (typeof chunk === 'string') {
        out.push(...expandSimpleTags(chunk, keyRef));
      } else {
        out.push(chunk);
      }
    }
    return out;
  };
  const extractText = node => {
    if (node === null || node === undefined) return '';
    if (typeof node === 'string') return node;
    if (typeof node === 'number') return String(node);
    if (typeof node === 'boolean') return '';
    if (Array.isArray(node)) return node.map(extractText).join('');
    if (node && typeof node === 'object' && node.type) {
      const props = node.props || ({});
      if (typeof props.children === 'string') return props.children;
      if (props.children) return extractText(props.children);
      return '';
    }
    return String(node || '');
  };
  const [mounted, setMounted] = useState(false);
  useEffect(() => {
    setMounted(true);
  }, []);
  const data = useMemo(() => {
    if (propData) return propData;
    if (content && typeof content === 'string') return parseYamlTableContent(content);
    if (!children) return [];
    if (typeof children === 'string') return parseYamlTableContent(children);
    const childrenArray = Array.isArray(children) ? children : [children];
    return parseYamlTableContent(childrenArray.map(extractText).join('').trim());
  }, [children, propData, content]);
  const columns = useMemo(() => {
    if (!data || data.length === 0) return [];
    const firstRow = data[0];
    if (!firstRow || typeof firstRow !== 'object') return [];
    return Object.keys(firstRow);
  }, [data]);
  if (!mounted) return null;
  if (!data || data.length === 0) return null;
  const rowKey = row => columns.map(c => row[c] || '').join('|');
  return <table>
      <thead>
        <tr>
          {columns.map(col => <th key={col}>{col.replaceAll('_', ' ')}</th>)}
        </tr>
      </thead>
      <tbody>
        {data.map(row => <tr key={rowKey(row)}>
            {columns.map(col => <td key={col} className={cellClassName(row[col])}>{processBadges(row[col])}</td>)}
          </tr>)}
      </tbody>
    </table>;
};

A container registry is a centralized service that stores and distributes your container images. Endor Labs lets you scan images directly from your registry, giving you full visibility into the security posture of your containerized workloads at scale. You can discover images across repositories, control the scope of your scans, and skip images you already scanned to avoid redundant work. You can also run consistent scans over time using saved scan plans.

A scan plan is a JSON file that defines the set of container images to scan, along with the registry and filters used to select them. It acts as a predefined template for selecting container images that you can verify and test ahead of time before the actual registry scan runs. Once saved, you can reuse the scan plan to scan the exact same set of images without querying the registry again, making recurring or batch scans consistent and easier to share across runs or environments.

With registry scanning, you can list all repositories and tags, or a filtered subset, in a registry without manually specifying each image. You can save an enumerated image list as a scan plan and reuse it later so the command scans the same set of images without re-querying the registry each time.

Endor Labs supports the following container registries:

* AWS ECR
* Azure ACR
* Docker Hub
* GitHub Container Registry (GHCR)
* Google Artifact Registry (GAR)
* JFrog Artifactory
* Quay
* Generic OCI-compliant registries

Use the `endorctl container registry` commands to list and scan images stored in your registry.

* [**List images from a registry**](#list-command): Use `endorctl container registry list` to preview which images match your filters before scanning. This lets you verify the scope and adjust filtering parameters such as `--include`, `--exclude`, `--recent`, and `--limit`. You can also save the results as a scan plan for the scan step.

* [**Scan images from a registry**](#scan-command): Use `endorctl container registry scan` to enumerate and scan container images from a registry in a single step. You can also provide a saved scan plan from the list command instead of enumerating the registry again.

Use a scan plan when you want to review the list of images before scanning. The scan plans make it easier to reuse these pre-qualified combinations of scanned parameters and ensure consistent results.

<Note>
  **Prerequisites for AWS ECR and Azure ACR registry scans**

  Install and configure the [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) to use AWS ECR and the [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) to use Azure ACR to authenticate and enumerate their corresponding container registries.
</Note>

## List command

The list command connects to your registry, enumerates container images based on your configured filters, and prints a summary with a table of image paths. You can also save the results as a scan plan to reuse with the scan command.

```bash theme={null}
endorctl container registry list --type=<type> [options]
```

You can apply filters such as `include`, `exclude`, `recent`, and `limit` to narrow down the images returned. If you provide a namespace and API credentials, the saved plan automatically excludes already scanned images, so it is ready to scan only new or updated images.

The command applies filters in the following order:

1. **include**
2. **exclude**
3. **recent**
4. **limit**

You can use the `endorctl container registry list` command with the following flags.

<YamlTable>
  {`


    - Flag: \`--type\`
    Environment_Variable: \`ENDOR_CONTAINER_REGISTRY_TYPE\`
    Type: string
    Description: Container registry type. See [supported container registries](/scan/containers/container-registry-scan/#supported-container-registries) for the registries and their corresponding values.

    - Flag: \`--host\`
    Environment_Variable: \`ENDOR_CONTAINER_REGISTRY_HOST\`
    Type: string
    Description: Registry server or host. See the supported container registries table for example formats. Required for Azure ACR and JFrog.

    - Flag: \`--insecure\`
    Environment_Variable: \`ENDOR_CONTAINER_REGISTRY_INSECURE\`
    Type: boolean
    Description: Allow HTTPS connections to the registry without verifying the TLS certificate. Use when connecting to registries with self-signed or otherwise untrusted certificates.

    - Flag: \`--registry-namespace\`
    Environment_Variable: \`ENDOR_CONTAINER_REGISTRY_NAMESPACE\`
    Type: string
    Description: The namespace or scope to list within. This flag is optional and is commonly used for the Docker Hub, GHCR, and JFrog Artifactory registries. For Docker Hub or GHCR, it is the organization or user name and for JFrog, it is the repository key.

    - Flag: \`--include\`
    Environment_Variable: \`ENDOR_CONTAINER_REGISTRY_INCLUDE\`
    Type: string
    Description: Regex to include repositories or tags. Matches the repository name without the registry server or domain, the full repository and tag, or the digest. If not set, the command includes all repositories and their tags.

    - Flag: \`--exclude\`
    Environment_Variable: \`ENDOR_CONTAINER_REGISTRY_EXCLUDE\`
    Type: string
    Description: Regex to exclude a subset of container image names by repository or by repository and tag. For example, \`--exclude='test-repo'\` excludes all tags in repositories matching \`test-repo\`, and \`--exclude='myapp:latest'\` excludes only the \`latest\` tag in repositories matching \`myapp\`.

    - Flag: \`--recent\`
    Environment_Variable: \`ENDOR_CONTAINER_REGISTRY_RECENT\`
    Type: string
    Description: Include only images updated within the given recent time window. Use a duration string such as \`24h\`, \`7d\`, or \`2d7h\`. Applied after include and exclude.

    - Flag: \`--limit\`
    Environment_Variable: \`ENDOR_CONTAINER_REGISTRY_LIMIT\`
    Type: integer
    Description: Limit the number of images in the result after the command applies all filters.

    - Flag: \`--include-untagged\`
    Environment_Variable: \`ENDOR_CONTAINER_REGISTRY_INCLUDE_UNTAGGED\`
    Type: boolean
    Description: Include untagged manifests when the registry type supports them.

    - Flag: \`--include-untagged-only\`
    Environment_Variable: \`ENDOR_CONTAINER_REGISTRY_INCLUDE_UNTAGGED_ONLY\`
    Type: boolean
    Description: Consider only untagged container images. Use this only when the registry type supports untagged container images.

    - Flag: \`--validate-tag-digest\`
    Environment_Variable: \`ENDOR_CONTAINER_REGISTRY_VALIDATE_TAG_DIGEST\`
    Type: boolean
    Description: Resolve and confirm digest through a registry HEAD request for each tag.

    - Flag: \`--architecture\`
    Environment_Variable: \`ENDOR_CONTAINER_REGISTRY_ARCHITECTURE\`
    Type: string
    Description: Preferred architecture for multi-architecture images, for example, \`amd64\`, \`arm64\`, or \`linux/arm64\`.

    - Flag: \`--timeout\`
    Environment_Variable: \`ENDOR_CONTAINER_REGISTRY_TIMEOUT\`
    Type: string
    Description: Command timeout duration, such as \`30s\`, \`1m\`, or \`5m\`. Default is \`30s\`.

    - Flag: \`--project-prefix\`
    Environment_Variable: \`ENDOR_CONTAINER_REGISTRY_PROJECT_PREFIX\`
    Type: string
    Description: Optional prefix for project names derived from repository path. Without a prefix, the project name uses the container image repository path.

    - Flag: \`--save-as-plan\`
    Environment_Variable: \`ENDOR_CONTAINER_REGISTRY_SAVE_AS_PLAN\`
    Type: string
    Description: Write the list output as a scan plan JSON file to use with \`endorctl container registry scan --scan-plan\`.

    - Flag: \`--scanned-only\`
    Environment_Variable: \`ENDOR_CONTAINER_REGISTRY_SCANNED_ONLY\`
    Type: boolean
    Description: Show only images that Endor Labs already scanned. Requires \`--namespace\` and API credentials. You cannot use this flag with \`--save-as-plan\`.

    - Flag: \`--exclude-scanned\`
    Environment_Variable: \`ENDOR_CONTAINER_REGISTRY_EXCLUDE_SCANNED\`
    Type: boolean
    Description: Exclude images that are already scanned from the output. Without this flag, already-scanned images are still skipped during scanning. The flag only affects what appears in the list output. If a tag points to a new digest, Endor Labs treats it as a new image and scans it. When saving with \`--save-as-plan\`, the saved plan always excludes scanned images regardless of this flag. Requires \`--namespace\` and API credentials.


    `}
</YamlTable>

## Scan command

The scan command runs Endor Labs container scans on a set of images. You can pass a saved scan plan from the list command or enumerate the registry with the same filter flags as list. The command pulls each image if needed, runs the scan, and by default removes pulled images after scanning. You must provide `--namespace` and API credentials. Images that are already scanned are automatically skipped.

* Scan using a saved scan plan:

  ```bash theme={null}
  endorctl container registry scan --namespace=<namespace> --scan-plan=<path> [options]
  ```

* Scan using a registry type. When you do not use `--scan-plan`, pass `--type`.

  ```bash theme={null}
  endorctl container registry scan --namespace=<namespace> --type=<type> [options]
  ```

You can use the `endorctl container registry scan` command with the following flags.

<YamlTable>
  {`


    - Flag: \`--namespace\`, \`-n\`
    Environment_Variable: \`ENDOR_NAMESPACE\`
    Type: string
    Description: Endor Labs namespace for the scan and for checking current scan status.

    - Flag: \`--scan-plan\`
    Environment_Variable: \`ENDOR_CONTAINER_REGISTRY_SCAN_PLAN\`
    Type: string
    Description: Path to a scan plan JSON file produced by \`endorctl container registry list --save-as-plan\`. Provide either \`--type\` or \`--scan-plan\`.

    - Flag: \`--show-scan-plan\`
    Environment_Variable: \`ENDOR_CONTAINER_REGISTRY_SHOW_SCAN_PLAN\`
    Type: boolean
    Description: Print the scan plan including registry, filters, counts, and image list before starting scans. Set to \`false\` to skip this output and start scanning immediately.

    - Flag: \`--reauth\`
    Environment_Variable: \`ENDOR_CONTAINER_REGISTRY_REAUTH\`
    Type: boolean
    Description: Try to refresh registry credentials if authentication fails. For ECR and ACR, this uses the AWS CLI or Azure CLI respectively to refresh credentials.

    - Flag: \`--keep-pulled-images\`
    Environment_Variable: \`ENDOR_CONTAINER_REGISTRY_KEEP_PULLED_IMAGES\`
    Type: boolean
    Description: Keep pulled images in the local daemon after scanning. By default, the command removes pulled images to free disk space.


    `}
</YamlTable>

### Supported container registries

The `endorctl container registry list` and `endorctl container registry scan` commands support the following container registries. Use the **Registry\_type** value for `--type` and the **Registry\_host** value for `--host`.

<YamlTable>
  {`


    - Name: AWS ECR
    Registry_type: \`aws.ecr\`
    Registry_host: \`<account-id>.dkr.ecr.<region>.amazonaws.com\`

    - Name: Azure ACR
    Registry_type: \`azure.acr\`
    Registry_host: \`<name>.azurecr.io\`

    - Name: Docker Hub
    Registry_type: \`dockerhub\`
    Registry_host: \`docker.io\`

    - Name: GitHub Container Registry
    Registry_type: \`ghcr\`
    Registry_host: \`ghcr.io\`

    - Name: Google Artifact Registry
    Registry_type: \`gar\`
    Registry_host: \`<location>-docker.pkg.dev\`

    - Name: JFrog Artifactory
    Registry_type: \`artifactory\`
    Registry_host: \`https://<org>.jfrog.io\`

    - Name: Quay
    Registry_type: \`quay\`
    Registry_host: \`quay.io\`

    - Name: Generic OCI-compliant Registries
    Registry_type: \`oci\`
    Registry_host: \`registry.example.com\`


    `}
</YamlTable>

<Note>
  You must specify the registry host with `--host` when you use Azure ACR or JFrog registries.

  For Quay registries, set `--host` only for self-hosted instances. You must also specify `--registry-namespace` with the Quay user or organization name to enumerate repositories.
</Note>

## Output format

The list and scan commands both produce output that includes summary lines and, when there are image rows, a table. The scan command shows this when you set `--show-scan-plan`.

If any image rows remain after filters, the command prints a table with the following columns:

<YamlTable>
  {`


    - Column: IMAGE
    Description: Image path in tag or digest form.
    - Column: DIGEST
    Description: Architecture-specific image digest.
    - Column: CREATED
    Description: RFC3339 UTC timestamp.
    - Column: UPDATED
    Description: RFC3339 UTC timestamp.
    - Column: MULTI-ARCH
    Description: Indicates if the given container image in the registry is a multi-architecture container image represented by a manifest list.
    - Column: ARCH
    Description: Selected architecture when the image is multi-architecture.
    - Column: LIST-DIGEST
    Description: Shortened manifest list digest for multi-architecture only.


    `}
</YamlTable>

### Scan plan output

The scan plan is a JSON file written by the `endorctl container registry list` command with `--save-as-plan` and read by the `scan` command with `--scan-plan`. When you run list with `--namespace` and API credentials, the saved plan excludes images that Endor Labs already scanned so that it is ready to scan only new or unscanned images. The structure is:

```yaml expandable theme={null}
parameters:
  registry_type: string          # required
  server: string                 # optional
  namespace: string              # optional
  account: string                # optional. Used only for Docker Hub and GHCR.
  repo_key: string               # optional. Used only for JFrog.
  architecture: string           # optional
  include: string                # optional
  exclude: string                # optional
  recent: string                 # optional
  limit: integer                 # optional
  include_untagged: boolean      # optional
  include_untagged_only: boolean # optional
  validate_tag_digest: boolean   # optional
  timeout_seconds: integer      # required

counts:
  repositories: integer
  tags: integer
  untagged_manifests: integer    # optional
  matching_repositories: integer # optional
  matching_tags: integer         # optional
  matching_untagged: integer     # optional
  ignored_repositories: integer  # optional
  ignored_tags: integer          # optional
  ignored_untagged: integer      # optional
  digest_validated_tags: integer # optional
  digest_mismatch_tags: integer  # optional
  digest_lookup_errors: integer  # optional

images:                          # array
  - path: string                 # full image reference, tag or digest
    created: string
    updated: string
    multi_arch: boolean          # optional
    arch: string                 # optional
    multi_arch_digest: string    # optional
```

## Container registry scanning with AWS ECR

The following commands use AWS ECR to show how to list images, apply filters, save a scan plan, and run scans. Use the appropriate `--type`, `--host`, and `--registry-namespace` values for other registries. See [supported container registries](#supported-container-registries) to learn more.

* List all images in an AWS ECR registry.

```bash theme={null}
endorctl container registry list --type aws.ecr
```

* Filter images updated in the last 7 days, include only tags matching `latest`, and exclude release candidate tags.

```bash theme={null}
endorctl container registry list --type aws.ecr --recent 7d --include '.*:latest' --exclude '.*:-rc.*'
```

* Save the generated image list to a JSON scan plan file for use with the `container registry scan` command.

```bash theme={null}
endorctl container registry list --type aws.ecr --save-as-plan registry-scan-plan.json
```

* List images including untagged manifests.

```bash theme={null}
endorctl container registry list --type aws.ecr --include-untagged
```

* List only images that match a preferred architecture such as `arm64` when the repository contains multi-architecture images.

```bash theme={null}
endorctl container registry list --type aws.ecr --architecture arm64
```

* Scan images defined in a previously saved scan plan file.

```bash theme={null}
endorctl container registry scan --namespace demo --type=aws.ecr --reauth --scan-plan aws_ecr_scan_plan.json
```

<Note>
  * AWS ECR authenticates using the AWS SDK default credential chain, which includes environment variables, shared credential files, and IAM roles.
  * For Docker Hub, use `--type=dockerhub` and omit `--reauth` because it requires access to Docker Hub credentials for automated reauthentication.
  * For Quay, use `--type=quay` and provide `--registry-namespace` with your Quay user or organization name. Omit `--reauth` because Quay requires manual login.
</Note>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Authentication fails when listing or scanning images">
    * Ensure your registry credentials are valid and that the registry type and host are correct. Use `--reauth` to refresh credentials when using AWS ECR or Azure ECR.

    * For Docker Hub, GHCR, and Quay, verify the environment variables or log in with the registry's CLI.

    * For Quay, use `docker login` with an OAuth token.

    * For Azure ACR and JFrog, verify that you set `--host`.
  </Accordion>

  <Accordion title="Scan plan includes images I already scanned">
    * The command excludes images that Endor Labs already scanned only when you run list with `--namespace` and valid API credentials. Without them, the saved plan includes all matching images.

    * Re-run `endorctl container registry list` with `--namespace` and `--exclude-scanned`, save a new plan with `--save-as-plan`, then run the scan command with that plan.
  </Accordion>

  <Accordion title="How to generate a scan plan for a JFrog registry?">
    Run the list command with your registry details and `--save-as-plan` to save the enumerated images to a JSON file.

    ```bash theme={null}
    endorctl container registry list --type artifactory --host jfrog-host --registry-namespace repo-key --save-as-plan registry-scan-plan.json
    ```

    Replace  `jfrog-host` with your JFrog host and `repo-key` with your repository key.
  </Accordion>

  <Accordion title="How to list images for a Quay registry?">
    Run the list command with `--type=quay` and `--registry-namespace` set to your Quay user or organization name.

    ```bash theme={null}
    endorctl container registry list --type=quay --registry-namespace myorg
    ```

    For a self-hosted Quay instance, set `--host` to your Quay host.

    ```bash theme={null}
    endorctl container registry list --type=quay --host http://localhost:8080 --registry-namespace myorg
    ```

    Replace `myorg` with your Quay user or organization name and `http://localhost:8080` with your self-hosted Quay registry URL.
  </Accordion>
</AccordionGroup>
