{"id":2428,"date":"2025-08-28T13:18:33","date_gmt":"2025-08-28T13:18:33","guid":{"rendered":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2025\/08\/28\/secure-by-design-a-shift-left-approach-with-testcontainers-docker-scout-and-hardened-images\/"},"modified":"2025-08-28T13:18:33","modified_gmt":"2025-08-28T13:18:33","slug":"secure-by-design-a-shift-left-approach-with-testcontainers-docker-scout-and-hardened-images","status":"publish","type":"post","link":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2025\/08\/28\/secure-by-design-a-shift-left-approach-with-testcontainers-docker-scout-and-hardened-images\/","title":{"rendered":"Secure by Design: A Shift-Left Approach with Testcontainers, Docker Scout, and Hardened Images"},"content":{"rendered":"<p>In today\u2019s fast-paced world of software development, product teams are expected to move quickly: building features, shipping updates, and reacting to user needs in real-time. But moving fast should never mean compromising on quality or security.<\/p>\n<p>Thanks to modern tooling, developers can now maintain high standards while accelerating delivery. In a previous article, we explored how Testcontainers <a href=\"https:\/\/www.docker.com\/blog\/shift-left-testing-with-testcontainers\/\">supports shift-left testing<\/a> by enabling fast and reliable integration tests within the inner dev loop. In this post, we\u2019ll look at the security side of this shift-left approach and how Docker can help move security earlier in the development lifecycle, using practical examples.<\/p>\n\n<h2 class=\"wp-block-heading\">A Shift-Left Approach: Testing a Movie Catalog API<\/h2>\n<p>We\u2019ll use a simple <a href=\"https:\/\/github.com\/GannaChernyshova\/movie-catalog\" target=\"_blank\">demo project<\/a> to walk through our workflow. This is a Node.js + TypeScript API backed by PostgreSQL and tested with Testcontainers.<\/p>\n<p>Movie API Endpoints:<\/p>\n<div class=\"wp-block-ponyo-table style__default\">\n<p>Method<\/p>\n<p>Endpoint<\/p>\n<p>Description<\/p>\n\n<p>POST<\/p>\n<p>\/movies<\/p>\n<p>Add a new movie to the catalog<\/p>\n\n<p>GET<\/p>\n<p>\/movies<\/p>\n<p>Retrieve all movies, sorted by title<\/p>\n\n<p>GET<\/p>\n<p>\/movies\/search?q=\u2026<\/p>\n<p>Search movies by title or description (fuzzy match)<\/p>\n\n<\/div>\n<p>Before deploying this app to production, we want to make sure it functions correctly and is free from critical vulnerabilities.<\/p>\n<h2 class=\"wp-block-heading\">Shift-Left Testing with Testcontainers: Recap<\/h2>\n<p>We verify the application against a real PostgreSQL instance by using <a href=\"https:\/\/testcontainers.com\/cloud\/\" target=\"_blank\">Testcontainers<\/a> to spin up containers for both the database and the application. A key advantage of Testcontainers is that it creates these containers dynamically during test execution. Another feature of the Testcontainers libraries is the ability to start containers directly from a Dockerfile. This allows us to run the containerized application along with any required services, such as databases, effectively reproducing the local environment needed to test the application at the API or end-to-end (E2E) level. This approach provides an additional layer of quality assurance and brings even more testing into the inner development loop.<\/p>\n<p>For a more detailed explanation of how Testcontainers enables a shift-left testing approach into the developer inner loop, refer to the<a href=\"https:\/\/www.docker.com\/blog\/shift-left-testing-with-testcontainers\/\"> introductory blog post<\/a>.<\/p>\n<p>Here\u2019s a beforeAll setup that prepares our test environment, including PostgreSQL and the application under development, started from the Dockerfile :<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\nbeforeAll(async () =&gt; {<br \/>\n     const network = await new Network().start();<br \/>\n     \/\/ 1. Start Postgres<br \/>\n     db = await new PostgreSqlContainer(&#8220;postgres:17.4&#8221;)<br \/>\n     .withNetwork(network)<br \/>\n     .withNetworkAliases(&#8220;postgres&#8221;)<br \/>\n     .withDatabase(&#8220;catalog&#8221;)<br \/>\n     .withUsername(&#8220;postgres&#8221;)<br \/>\n     .withPassword(&#8220;postgres&#8221;)<br \/>\n     .withCopyFilesToContainer([<br \/>\n       {<br \/>\n         source: path.join(__dirname, &#8220;..\/dev\/db\/1-create-schema.sql&#8221;),<br \/>\n         target: &#8220;\/docker-entrypoint-initdb.d\/1-create-schema.sql&#8221;<br \/>\n       },<br \/>\n     ])<br \/>\n     .start();<br \/>\n     \/\/ 2.  Build movie catalog API container from the Dockerfile<br \/>\n     const container = await GenericContainer<br \/>\n       .fromDockerfile(&#8220;..\/movie-catalog&#8221;)<br \/>\n       .withTarget(&#8220;final&#8221;)<br \/>\n       .withBuildkit()<br \/>\n       .build();<br \/>\n    \/\/ 3. Start movie catalog API container with environment variables for DB connection<br \/>\n     app = await container<br \/>\n       .withNetwork(network)<br \/>\n       .withExposedPorts(3000)<br \/>\n       .withEnvironment({<br \/>\n           PGHOST: &#8220;postgres&#8221;,<br \/>\n           PGPORT: &#8220;5432&#8221;,<br \/>\n           PGDATABASE: &#8220;catalog&#8221;,<br \/>\n           PGUSER: &#8220;postgres&#8221;,<br \/>\n           PGPASSWORD: &#8220;postgres&#8221;,<br \/>\n         })<br \/>\n       .withWaitStrategy(Wait.forListeningPorts())<br \/>\n       .start();<br \/>\n   }, 120000);\n<\/div>\n<p>We can now test the movie catalog API:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\nit(&#8220;should create and retrieve a movie&#8221;, async () =&gt; {<br \/>\n     const baseUrl = `http:\/\/${app.getHost()}:${app.getMappedPort(3000)}`;<br \/>\n     const payload = {<br \/>\n       title: &#8220;Interstellar&#8221;,<br \/>\n       director: &#8220;Christopher Nolan&#8221;,<br \/>\n       genres: [&#8220;sci-fi&#8221;],<br \/>\n       releaseYear: 2014,<br \/>\n       description: &#8220;Space and time exploration&#8221;<br \/>\n     };\n<p>     const response = await axios.post(`${baseUrl}\/movies`, payload);<br \/>\n     expect(response.status).toBe(201);<br \/>\n     expect(response.data.title).toBe(&#8220;Interstellar&#8221;);<br \/>\n   }, 120000);\n<\/p><\/div>\n<p>This approach allows us to validate that:<\/p>\n<p>The application is properly containerized and starts successfully.<\/p>\n<p>The API behaves correctly in a containerized environment with a real database.<\/p>\n<p>However, that\u2019s just one part of the quality story. Now, let\u2019s turn our attention to the security aspects of the application under development.<\/p>\n\n<h2 class=\"wp-block-heading\">Introducing Docker Scout and Docker Hardened Images\u00a0<\/h2>\n<p>To follow modern best practices, we want to <a href=\"https:\/\/docs.docker.com\/get-started\/workshop\/02_our_app\/\" target=\"_blank\">containerize the app<\/a> and eventually deploy it to production. Before doing so, we must ensure the image is secure by using <a href=\"https:\/\/www.docker.com\/products\/docker-scout\/\">Docker Scout<\/a>.<\/p>\n<p>Our Dockerfile takes a multi-stage build approach and is based on the node:22-slim image.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n###########################################################<br \/>\n# Stage: base<br \/>\n# This stage serves as the base for all of the other stages.<br \/>\n# By using this stage, it provides a consistent base for both<br \/>\n# the dev and prod versions of the image.<br \/>\n###########################################################<br \/>\nFROM node:22-slim AS base<br \/>\nWORKDIR \/usr\/local\/app<br \/>\nRUN useradd -m appuser &amp;&amp; chown -R appuser \/usr\/local\/app<br \/>\nUSER appuser<br \/>\nCOPY &#8211;chown=appuser:appuser package.json package-lock.json .\/\n<p>###########################################################<br \/>\n# Stage: dev<br \/>\n# This stage is used to run the application in a development<br \/>\n# environment. It installs all app dependencies and will<br \/>\n# start the app in a dev mode that will watch for file changes<br \/>\n# and automatically restart the app.<br \/>\n###########################################################<br \/>\nFROM base AS dev<br \/>\nENV NODE_ENV=development<br \/>\nRUN npm ci &#8211;ignore-scripts<br \/>\nCOPY &#8211;chown=appuser:appuser .\/src .\/src<br \/>\nEXPOSE 3000<br \/>\nCMD [&#8220;npx&#8221;, &#8220;nodemon&#8221;, &#8220;src\/app.js&#8221;]<\/p>\n<p>###########################################################<br \/>\n# Stage: final<br \/>\n# This stage serves as the final image for production. It<br \/>\n# installs only the production dependencies.<br \/>\n###########################################################<br \/>\n# Deps: install only prod deps<br \/>\nFROM base AS prod-deps<br \/>\nENV NODE_ENV=production<br \/>\nRUN npm ci &#8211;production &#8211;ignore-scripts &amp;&amp; npm cache clean &#8211;force<br \/>\n# Final: clean prod image<br \/>\nFROM base AS final<br \/>\nWORKDIR \/usr\/local\/app<br \/>\nCOPY &#8211;from=prod-deps \/usr\/local\/app\/node_modules .\/node_modules<br \/>\nCOPY .\/src .\/src<br \/>\nEXPOSE 3000<br \/>\nCMD [ &#8220;node&#8221;, &#8220;src\/app.js&#8221; ]\n<\/p><\/div>\n<p>Let\u2019s build our image with SBOM and provenance metadata. First, make sure that the containerd image store is <a href=\"https:\/\/docs.docker.com\/desktop\/features\/containerd\/?#enable-the-containerd-image-store\" target=\"_blank\">enabled in Docker Desktop<\/a>. We\u2019ll also use the buildx command ( a Docker CLI plugin that extends the docker build) with the \u2013provenance=true \u00a0and \u2013sbom=true flags. These options attach<a href=\"https:\/\/docs.docker.com\/build\/metadata\/attestations\/\" target=\"_blank\"> build attestations<\/a> to the image, which Docker Scout uses to provide more detailed and accurate security analysis.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\ndocker buildx build &#8211;provenance=true &#8211;sbom=true -t movie-catalog-service:v1 .\n<\/div>\n<p>Then set up a Docker organization with security policies and scan the image with Docker Scout:\u00a0<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\ndocker scout config organization demonstrationorg<br \/>\ndocker scout quickview movie-catalog-service:v1\n<\/div>\n<div class=\"wp-block-ponyo-image\"><\/div>\n<p><em>Figure 1: Docker Scout cli quickview output for node:22 based movie-catalog-service image<\/em><\/p>\n<p>Docker Scout also offers a visual analysis via Docker Desktop.<\/p>\n<div class=\"wp-block-ponyo-image\"><\/div>\n<p><em>Figure 2: Image layers and CVEs view in Docker Desktop for node:22 based movie-catalog-service image<\/em><\/p>\n<p>In this example, no vulnerabilities were found in the application layer. However, several CVEs were introduced by the base node:22-slim image, including a high-severity CVE-2025-6020, a vulnerability present in Debian 12. This means that any Node.js image based on Debian 12 inherits this vulnerability. A common way to address this is by switching to an Alpine-based Node image, which does not include this CVE. However, Alpine uses musl libc instead of glibc, which can lead to compatibility issues depending on your application\u2019s runtime requirements and deployment environment.<\/p>\n<p>So, what\u2019s a more secure and compatible alternative?<\/p>\n<p>That\u2019s where<a href=\"https:\/\/www.docker.com\/products\/hardened-images\/\"> Docker Hardened Images (DHI)<\/a> come in. These images follow a distroless philosophy, removing unnecessary components to significantly reduce the attack surface. The result? Smaller images that pull faster, run leaner, and provide a secure-by-default foundation for production workloads:<\/p>\n<p>Near-zero exploitable CVEs: Continuously updated, vulnerability-scanned, and published with signed attestations to minimize patch fatigue and eliminate false positives.<\/p>\n<p>Seamless migration: Drop-in replacements for popular base images, with -dev variants available for multi-stage builds.<\/p>\n<p>Up to 95% smaller attack surface: Unlike traditional base images that include full OS stacks with shells and package managers, distroless images retain only the essentials needed to run your app.<\/p>\n<p>Built-in supply chain security: Each image includes signed SBOMs, VEX documents, and SLSA provenance for audit-ready pipelines.<\/p>\n<p>For developers, DHI means fewer CVE-related disruptions, faster CI\/CD pipelines, and trusted images you can use with confidence.<\/p>\n<h2 class=\"wp-block-heading\">Making the Switch to Docker Hardened Images<\/h2>\n<p>Switching to a Docker Hardened Image is straightforward. All we need to do is replace the base image node:22-slim with a DHI equivalent.<\/p>\n<p>Docker Hardened Images come in two variants:<\/p>\n<p>Dev variant (demonstrationorg\/dhi-node:22-dev) \u2013 includes a shell and package managers, making it suitable for building and testing.<\/p>\n<p>Runtime variant (demonstrationorg\/dhi-node:22) \u2013 stripped down to only the essentials, providing a minimal and secure footprint for production.<\/p>\n<p>This makes them perfect for use in multi-stage Dockerfiles. We can build the app in the dev image, then copy the built application into the runtime image, which will serve as the base for production.<\/p>\n<p>Here\u2019s what the updated Dockerfile would look like:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n###########################################################<br \/>\n# Stage: base<br \/>\n# This stage serves as the base for all of the other stages.<br \/>\n# By using this stage, it provides a consistent base for both<br \/>\n# the dev and prod versions of the image.<br \/>\n###########################################################<br \/>\n# Changed node:22 to dhi-node:22-dev<br \/>\nFROM demonstrationorg\/dhi-node:22-dev AS base<br \/>\nWORKDIR \/usr\/local\/app<br \/>\n# DHI comes with nonroot user built-in.<br \/>\nCOPY &#8211;chown=nonroot package.json package-lock.json .\/\n<p>###########################################################<br \/>\n# Stage: dev<br \/>\n# This stage is used to run the application in a development<br \/>\n# environment. It installs all app dependencies and will<br \/>\n# start the app in a dev mode that will watch for file changes<br \/>\n# and automatically restart the app.<br \/>\n###########################################################<br \/>\nFROM base AS dev<br \/>\nENV NODE_ENV=development<br \/>\nRUN npm ci &#8211;ignore-scripts<br \/>\n# DHI comes with nonroot user built-in.<br \/>\nCOPY &#8211;chown=nonroot .\/src .\/src<br \/>\nEXPOSE 3000<br \/>\nCMD [&#8220;npx&#8221;, &#8220;nodemon&#8221;, &#8220;src\/app.js&#8221;]<\/p>\n<p>###########################################################<br \/>\n# Stage: final<br \/>\n# This stage serves as the final image for production. It<br \/>\n# installs only the production dependencies.<br \/>\n###########################################################<br \/>\n# Deps: install only prod deps<br \/>\nFROM base AS prod-deps<br \/>\nENV NODE_ENV=production<br \/>\nRUN npm ci &#8211;production &#8211;ignore-scripts &amp;&amp; npm cache clean &#8211;force<br \/>\n# Final: clean prod image<br \/>\n# Changed base to dhi-node:22<br \/>\nFROM demonstrationorg\/dhi-node:22 AS final<br \/>\nWORKDIR \/usr\/local\/app<br \/>\nCOPY &#8211;from=prod-deps \/usr\/local\/app\/node_modules .\/node_modules<br \/>\nCOPY .\/src .\/src<br \/>\nEXPOSE 3000<br \/>\nCMD [ &#8220;node&#8221;, &#8220;src\/app.js&#8221; ]\n<\/p><\/div>\n<p>Let\u2019s rebuild and scan the new image:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\ndocker buildx build &#8211;provenance=true &#8211;sbom=true -t movie-catalog-service-dhi:v1 .<br \/>\ndocker scout quickview movie-catalog-service-dhi:v1\n<\/div>\n<div class=\"wp-block-ponyo-image\"><\/div>\n<p><em>Figure 3: Docker Scout cli quickview output for dhi-node:22 based movie-catalog-service image<\/em><\/p>\n\n<p>As you can see, all critical and high CVEs are gone, thanks to the clean and minimal footprint of the Docker Hardened Image.<\/p>\n<p>One of the key benefits of using DHI is the security SLA it provides. If a new CVE is discovered, the DHI team commits to resolving:<\/p>\n<p>Critical and high vulnerabilities within 7 days of a patch becoming available,<\/p>\n<p>Medium and low vulnerabilities within 30 days.<\/p>\n<p>This means you can significantly reduce your CVE remediation burden and give developers more time to focus on innovation and feature development instead of chasing vulnerabilities.<\/p>\n<h2 class=\"wp-block-heading\">Comparing images with Docker Scout<\/h2>\n<p>Let\u2019s also look at the image size and package count advantages of using distroless Hardened Images.<\/p>\n<p>Docker Scout offers a helpful command docker scout compare , that allows you to analyze and compare two images. We\u2019ll use it to evaluate the difference in size and package footprint between node:22-slim and dhi-node:22 based images.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\ndocker scout compare local:\/\/movie-catalog-service:v1 &#8211;to local:\/\/movie-catalog-service-dhi:v1\n<\/div>\n<div class=\"wp-block-ponyo-image\"><\/div>\n<p><em>Figure 4: Comparison of the node:22 and dhi-node:22 based movie-catalog-service images<\/em><\/p>\n\n<p>As you can see, the original node:22-slim based image was 80 MB in size and included 427 packages, while the dhi-node:22 based image is just 41 MB with only 123 packages.\u00a0<\/p>\n<p>By switching to a Docker Hardened Image, we reduced the image size by nearly 50 percent and cut down the number of packages by more than three times, significantly reducing the attack surface.<\/p>\n<h2 class=\"wp-block-heading\">Final Step: Validate with local API tests<\/h2>\n<p>Last but not least, after migrating to a DHI base image, we should verify that the application still functions as expected.<\/p>\n<p>Since we\u2019ve already implemented Testcontainers-based tests, we can easily ensure that the API remains accessible and behaves correctly.<\/p>\n<p>Let\u2019s run the tests using the npm test command.\u00a0<\/p>\n<div class=\"wp-block-ponyo-image\"><\/div>\n<p><em>Figure 5: Local API test execution results<\/em><\/p>\n\n<p>As you can see, the container was built and started successfully. In less than 20 seconds, we were able to verify that the application functions correctly and integrates properly with Postgres.<\/p>\n<p>At this point, we can push the changes to the remote repository, confident that the application is both secure and fully functional, and move on to the next task.\u00a0<\/p>\n<h2 class=\"wp-block-heading\">Further integration with external security tools<\/h2>\n<p>In addition to providing a minimal and secure base image, Docker Hardened Images include a comprehensive set of attestations. These include a Software Bill of Materials (SBOM), which details all components, libraries, and dependencies used during the build process, as well as Vulnerability Exploitability eXchange (VEX). VEX offers contextual insights into vulnerabilities, specifying whether they are actually exploitable in a given environment, helping teams prioritize remediation.<\/p>\n<p>Let\u2019s say you\u2019ve committed your code changes, built the application, and pushed a container image. Now you want to verify the security posture using an external scanning tool you already use, such as Grype or Trivy. That requires vulnerability information in a compatible format, which Docker Scout can generate for you.<\/p>\n<p>First, you can view the list of available attestations using the docker scout attest command:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\ndocker scout attest list demonstrationorg\/movie-catalog-service-dhi:v1 &#8211;platform linux\/arm64\n<\/div>\n<p>This command returns a detailed list of attestations bundled with the image. For example, you might see two OpenVEX files: one for the DHI base image and another for any custom exceptions (like no-dsa) specific to your image.<\/p>\n<p>Then, to integrate this information with external tools, you can export the VEX data into a vex.json file. Starting Docker Scout v1.18.3 you can use the docker scout vex get command to get the merged VEX document from all VEX attestations:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\ndocker scout vex get demonstrationorg\/movie-catalog-service-dhi:v1 &#8211;output vex.json\n<\/div>\n<p>This generates a vex.json file containing all VEX statements for the specified image. Tools that support VEX can then use this file to suppress known non-exploitable CVEs.<\/p>\n<p>To use the VEX information with Grype or Trivy, pass the \u2013vex flag during scanning:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\ntrivy image demonstrationorg\/movie-catalog-service-dhi:v1 &#8211;vex vex.json\n<\/div>\n<p>This ensures your security scanning results are consistent across tools, leveraging the same set of vulnerability contexts provided by Docker Scout.<\/p>\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n<p>Shifting left is about more than just early testing. It\u2019s a proactive mindset for building secure, production-ready software from the beginning.<\/p>\n<p>This shift-left approach combines:<\/p>\n<p>Real infrastructure testing using Testcontainers<\/p>\n<p>End-to-end supply chain visibility and actionable insights with Docker Scout<\/p>\n<p>Trusted, minimal base images through Docker Hardened Images<\/p>\n<p>Together, these tools help catch issues early, improve compliance, and reduce security risks in the software supply chain.<\/p>\n<p>Learn more and <a href=\"https:\/\/www.docker.com\/products\/hardened-images\/#getstarted\">request access to Docker Hardened Images!<\/a><\/p>","protected":false},"excerpt":{"rendered":"<p>In today\u2019s fast-paced world of software development, product teams are expected to move quickly: building features, shipping updates, and reacting [&hellip;]<\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[4],"tags":[],"class_list":["post-2428","post","type-post","status-publish","format-standard","hentry","category-docker"],"_links":{"self":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/2428","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/comments?post=2428"}],"version-history":[{"count":0,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/2428\/revisions"}],"wp:attachment":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/media?parent=2428"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/categories?post=2428"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/tags?post=2428"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}