<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Giovanni Leopoldo Rozza</title>
    <description>The latest articles on DEV Community by Giovanni Leopoldo Rozza (@giovanni_leopoldorozza_5).</description>
    <link>https://dev.to/giovanni_leopoldorozza_5</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1956450%2F8f56740e-46ed-4a97-bd01-d9387eede674.png</url>
      <title>DEV Community: Giovanni Leopoldo Rozza</title>
      <link>https://dev.to/giovanni_leopoldorozza_5</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/giovanni_leopoldorozza_5"/>
    <language>en</language>
    <item>
      <title>What Spring Boot actually does with your configuration</title>
      <dc:creator>Giovanni Leopoldo Rozza</dc:creator>
      <pubDate>Tue, 29 Sep 2026 01:39:09 +0000</pubDate>
      <link>https://dev.to/giovanni_leopoldorozza_5/what-spring-boot-actually-does-with-your-configuration-2k5o</link>
      <guid>https://dev.to/giovanni_leopoldorozza_5/what-spring-boot-actually-does-with-your-configuration-2k5o</guid>
      <description>&lt;p&gt;I maintain &lt;a href="https://github.com/rgiovann/spring-config-guard" rel="noopener noreferrer"&gt;spring-config-guard&lt;/a&gt;, a static-analysis CLI that reads &lt;code&gt;application.yml&lt;/code&gt;/&lt;code&gt;.properties&lt;/code&gt; files and reports security misconfigurations: exposed Actuator endpoints, hardcoded credentials, unencrypted Kafka, and so on. A linter like this is only as good as its model of how Spring Boot resolves configuration. If the model is wrong, it reports risks that don't exist, or misses ones that do.&lt;/p&gt;

&lt;p&gt;So I started checking behavior against a running Spring Boot 4.1.1 app instead of relying on what the documentation implies. Several results surprised me, and some changed how the linter works.&lt;/p&gt;

&lt;p&gt;Throughout the article I mark where each claim comes from: &lt;strong&gt;(docs)&lt;/strong&gt; when the Spring documentation states it, &lt;strong&gt;(observed)&lt;/strong&gt; when I saw it in Spring Boot 4.1.1 with a reproducible test, and &lt;strong&gt;(source)&lt;/strong&gt; when I read it in the implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  The method: &lt;code&gt;/actuator/configprops&lt;/code&gt; next to &lt;code&gt;/actuator/env&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;My first instinct was to compare the linter's view with &lt;code&gt;/actuator/env&lt;/code&gt;. That works for simple overrides, but not for most interesting cases.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/actuator/env&lt;/code&gt; lists each &lt;strong&gt;property source&lt;/strong&gt; separately, with its raw keys. If &lt;code&gt;application.yml&lt;/code&gt; defines a list and &lt;code&gt;application-prod.yml&lt;/code&gt; overrides it, &lt;code&gt;/env&lt;/code&gt; shows both sources, each with its own keys. It doesn't tell you which one wins: merging and binding happen later, in Spring's &lt;code&gt;Binder&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/actuator/configprops&lt;/code&gt; shows the values after binding into &lt;code&gt;@ConfigurationProperties&lt;/code&gt; classes, with precedence and merging applied. For properties bound that way, it is a much better picture of what the application gets than &lt;code&gt;/env&lt;/code&gt;. (It doesn't cover values read through &lt;code&gt;@Value&lt;/code&gt; or directly from the &lt;code&gt;Environment&lt;/code&gt;.) So for each binding question below, I bound a property into a small record in the test app and read what &lt;code&gt;configprops&lt;/code&gt; reported:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@ConfigurationProperties&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"app"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;BenchmarkProperties&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bracketMap&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ListCases&lt;/span&gt; &lt;span class="n"&gt;lists&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1. Actuator: access and exposure are two different things
&lt;/h3&gt;

&lt;p&gt;This one matters most for security. An endpoint is available over HTTP only when its &lt;strong&gt;access&lt;/strong&gt; is permitted &lt;strong&gt;and&lt;/strong&gt; it is &lt;strong&gt;exposed&lt;/strong&gt; over HTTP (docs). &lt;code&gt;management.endpoints.web.exposure.include&lt;/code&gt; only answers the second question.&lt;/p&gt;

&lt;p&gt;I started the same app once per configuration, always with &lt;code&gt;exposure.include=*&lt;/code&gt;, and recorded which sensitive endpoints &lt;code&gt;/actuator&lt;/code&gt; linked to (observed):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;With &lt;code&gt;exposure.include=*&lt;/code&gt; and...&lt;/th&gt;
&lt;th&gt;Sensitive endpoints available over HTTP&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;nothing else&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;env&lt;/code&gt;, &lt;code&gt;threaddump&lt;/code&gt;, &lt;code&gt;configprops&lt;/code&gt;, &lt;code&gt;beans&lt;/code&gt;, &lt;code&gt;loggers&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;exposure.exclude=env,heapdump&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the same, without &lt;code&gt;env&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;endpoints.access.default=none&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;endpoints.access.max-permitted=none&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;management.server.port=-1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;none (HTTP endpoints disabled)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;endpoints.access.default=unrestricted&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the default set, &lt;strong&gt;plus &lt;code&gt;heapdump&lt;/code&gt; and &lt;code&gt;shutdown&lt;/code&gt;&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;endpoints.access.default=read-only&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the default set, plus &lt;code&gt;heapdump&lt;/code&gt; (not &lt;code&gt;shutdown&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;access.default=none&lt;/code&gt; and &lt;code&gt;env.access=unrestricted&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;env&lt;/code&gt; only&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;What to take from it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;exclude&lt;/code&gt; wins over &lt;code&gt;include&lt;/code&gt;&lt;/strong&gt; (docs). &lt;code&gt;include=*&lt;/code&gt; with &lt;code&gt;exclude=env,heapdump&lt;/code&gt; is a reasonable pattern.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;heapdump&lt;/code&gt; and &lt;code&gt;shutdown&lt;/code&gt; have restricted access by default&lt;/strong&gt; (docs), so &lt;code&gt;include=*&lt;/code&gt; alone doesn't expose them. A global &lt;code&gt;access.default=unrestricted&lt;/code&gt; lifts that restriction, and the wildcard then exposes both (observed). &lt;code&gt;heapdump&lt;/code&gt; is a memory dump of your application, secrets included: a permissive global default "to make things work" reaches further than the endpoints you had in mind.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;read-only&lt;/code&gt; is about operations, not endpoints&lt;/strong&gt; (docs). With &lt;code&gt;access.default=read-only&lt;/code&gt;, &lt;code&gt;heapdump&lt;/code&gt; (a read operation) is available, but &lt;code&gt;shutdown&lt;/code&gt; (write only) is not (observed).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The older &lt;code&gt;enabled&lt;/code&gt; keys still work, but move off them.&lt;/strong&gt; &lt;code&gt;management.endpoints.enabled-by-default&lt;/code&gt; has been deprecated since 3.4 in favor of &lt;code&gt;management.endpoints.access.default&lt;/code&gt;, and the per-endpoint &lt;code&gt;enabled&lt;/code&gt; keys are part of the older endpoint enable/disable model. In 4.1.1 both are still honored (observed); prefer the &lt;code&gt;access&lt;/code&gt; keys.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't set both models on one endpoint.&lt;/strong&gt; In 4.1.1, setting &lt;code&gt;management.endpoint.env.access&lt;/code&gt; and &lt;code&gt;management.endpoint.env.enabled&lt;/code&gt; together stops the application from starting: the two are reported as mutually exclusive (observed).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The linter used to read only &lt;code&gt;exposure.include&lt;/code&gt; and each endpoint's own &lt;code&gt;access&lt;/code&gt;/&lt;code&gt;enabled&lt;/code&gt;. Against this table, that produced six false positives and two false negatives (the missed &lt;code&gt;heapdump&lt;/code&gt; and &lt;code&gt;shutdown&lt;/code&gt;). It now resolves access and exposure the way the table shows.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Bracketed map keys
&lt;/h3&gt;

&lt;p&gt;Some properties are maps whose keys contain dots, such as Kafka client settings. Bracket notation keeps the key intact (docs):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="err"&gt;spring.kafka.properties[sasl.jaas.config]=...&lt;/span&gt;
&lt;span class="err"&gt;spring.kafka.properties[security.protocol]=SASL_SSL&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;For a &lt;code&gt;Map&amp;lt;String, String&amp;gt;&lt;/code&gt;, &lt;code&gt;x.map[a.b]&lt;/code&gt; and &lt;code&gt;x.map.a.b&lt;/code&gt; bind the same entry, &lt;code&gt;a.b&lt;/code&gt;&lt;/strong&gt; (docs, observed).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maps merge key by key across profiles&lt;/strong&gt; (observed): a profile adding one entry keeps the base's other entries, and a profile overriding one entry replaces only that one. Lists behave differently (next section).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Brackets matter even when the characters are allowed.&lt;/strong&gt; In this &lt;code&gt;Map&amp;lt;String, String&amp;gt;&lt;/code&gt; binding test, &lt;code&gt;app.map.com.foo-bar=A&lt;/code&gt; and &lt;code&gt;app.map.com.foobar=B&lt;/code&gt;, without brackets, produced two map keys, &lt;code&gt;com.foo-bar&lt;/code&gt; and &lt;code&gt;com.foobar&lt;/code&gt;, but both got the same value: the dash was kept in the key name, while the value lookup treated the two spellings as one property (observed). With brackets, &lt;code&gt;app.map[com.foo-bar]&lt;/code&gt; and &lt;code&gt;app.map[com.foobar]&lt;/code&gt; got their own values.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In YAML, bracketed keys must be quoted (docs), and Spring's YAML loader attaches them to their parent without a dot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;kafka&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[security.protocol]"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SASL_SSL&lt;/span&gt;   &lt;span class="c1"&gt;# spring.kafka.properties[security.protocol]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same holds for a quoted index: &lt;code&gt;"[0]":&lt;/code&gt; under a key is list item &lt;code&gt;0&lt;/code&gt; (observed). The linter originally joined keys with a dot (&lt;code&gt;x.[0]&lt;/code&gt;), so a wildcard written as &lt;code&gt;include: {"[0]": "*"}&lt;/code&gt; went undetected.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Lists are replaced whole
&lt;/h3&gt;

&lt;p&gt;When a list is configured in more than one place, the whole list is replaced, lists of objects included: fields a profile doesn't write are not inherited from the base (docs). What I checked beyond that (observed):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The two tested formats behave as one list.&lt;/strong&gt; A comma-separated value in &lt;code&gt;application.properties&lt;/code&gt; (&lt;code&gt;app.hosts=a,b&lt;/code&gt;) and an indexed list in &lt;code&gt;application.yml&lt;/code&gt; (&lt;code&gt;app.hosts[0]&lt;/code&gt;) are the same list; the &lt;code&gt;.properties&lt;/code&gt; value wins as a whole.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Elements are trimmed.&lt;/strong&gt; &lt;code&gt;app.hosts=a, b ,c&lt;/code&gt; binds as &lt;code&gt;[a, b, c]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An empty value is an empty list.&lt;/strong&gt; &lt;code&gt;app.hosts=&lt;/code&gt; binds &lt;code&gt;[]&lt;/code&gt;, not &lt;code&gt;[""]&lt;/code&gt;, and clears a list from a lower-precedence source. YAML &lt;code&gt;[]&lt;/code&gt; does the same (in &lt;code&gt;/actuator/env&lt;/code&gt; it shows as an empty string).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A profile can't skip an index.&lt;/strong&gt; Defining only &lt;code&gt;servers[1].url&lt;/code&gt; doesn't leave a gap: the application fails to start, reporting elements that were left unbound.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. A scalar and a map on the same key
&lt;/h3&gt;

&lt;p&gt;Base: &lt;code&gt;app.feature=enabled&lt;/code&gt;. Profile: &lt;code&gt;app.feature.mode=strict&lt;/code&gt;. In my tests, neither was removed from the property sources, and the &lt;strong&gt;target type&lt;/strong&gt; decided which one mattered: a &lt;code&gt;String&lt;/code&gt; field bound the scalar, a &lt;code&gt;Map&lt;/code&gt; or an object bound the sub-keys, even when the ignored shape came from the higher-precedence profile (observed).&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Where configuration comes from
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;application.yml&lt;/code&gt; and &lt;code&gt;application.properties&lt;/code&gt; in the same location both load; &lt;code&gt;.properties&lt;/code&gt; wins a conflict&lt;/strong&gt; (docs, observed). The linter used to drop one of the two files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A profile written in two places.&lt;/strong&gt; Profile-specific files take precedence over non-specific ones (docs). With both &lt;code&gt;application-prod.yml&lt;/code&gt; and a &lt;code&gt;spring.config.activate.on-profile: prod&lt;/code&gt; block inside &lt;code&gt;application.yml&lt;/code&gt;, in the tested configuration both contributed and &lt;code&gt;application-prod.yml&lt;/code&gt; won the conflict (observed).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Several locations feed one environment, in order.&lt;/strong&gt; At runtime, Spring Boot searches the classpath root, classpath &lt;code&gt;/config&lt;/code&gt;, the current directory, &lt;code&gt;./config/&lt;/code&gt; and its immediate subdirectories (docs). These locations are not merged with equal priority: their order determines precedence, and external files take precedence over packaged ones (docs). Since &lt;code&gt;src/main/resources&lt;/code&gt; ends up on the classpath root, a project with files there and in &lt;code&gt;config/&lt;/code&gt; has one combined configuration, and a risky combination split across them (&lt;code&gt;allowed-origins: "*"&lt;/code&gt; in one, &lt;code&gt;allow-credentials: true&lt;/code&gt; in the other) is easy to miss in review. spring-config-guard evaluates each directory on its own, so it prints a coverage warning when it sees config in more than one location.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. Spring Cloud Stream's Kafka binder has its own precedence
&lt;/h3&gt;

&lt;p&gt;With Spring Cloud Stream, Kafka client settings don't come only from &lt;code&gt;spring.kafka.*&lt;/code&gt;. The binder builds each client's configuration from (docs):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Spring Boot's &lt;code&gt;spring.kafka.*&lt;/code&gt; properties,&lt;/li&gt;
&lt;li&gt;overridden by &lt;code&gt;spring.cloud.stream.kafka.binder.configuration.*&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;overridden by &lt;code&gt;consumer-properties.*&lt;/code&gt; / &lt;code&gt;producer-properties.*&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So &lt;code&gt;security.protocol: SASL_PLAINTEXT&lt;/code&gt; in the binder's &lt;code&gt;configuration&lt;/code&gt; map sends credentials unencrypted even when &lt;code&gt;spring.kafka.security.protocol&lt;/code&gt; says &lt;code&gt;SASL_SSL&lt;/code&gt;. A check that reads only &lt;code&gt;spring.kafka.*&lt;/code&gt; misses it, and the linter did, until a real repository showed it.&lt;/p&gt;

&lt;p&gt;A named binder can also have its own &lt;code&gt;spring.cloud.stream.binders.&amp;lt;name&amp;gt;.environment.*&lt;/code&gt;, optionally inheriting the application's environment (docs). The implementation adds those entries as the first property source of that binder's environment, ahead of the inherited configuration (source: &lt;code&gt;DefaultBinderFactory&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Two lessons from building the linter itself
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;Set.of&lt;/code&gt; doesn't provide a deterministic iteration order.&lt;/strong&gt; One rule built a message by iterating a &lt;code&gt;Set.of(...)&lt;/code&gt; of endpoint names. In our test, running the same jar five times on the same inputs produced between two and five different outputs in 8 of the 12 reference projects. For a tool that gates CI and whose reports get diffed, output has to be deterministic: iterate lists, and sort results with a total order.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Heuristics hide things.&lt;/strong&gt; To avoid flagging values like &lt;code&gt;token-validity-in-seconds: 86400&lt;/code&gt;, the secrets rule skipped purely numeric values. It also skipped &lt;code&gt;ssl.keystore.password: 123456&lt;/code&gt;, found in a real sample repository. The fix narrowed the heuristic: a key that &lt;em&gt;ends&lt;/em&gt; in a secret word names the secret itself, so a numeric value there is reported.&lt;/p&gt;

&lt;h3&gt;
  
  
  Takeaways
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;For properties bound through &lt;code&gt;@ConfigurationProperties&lt;/code&gt;, &lt;code&gt;/actuator/configprops&lt;/code&gt; shows what the application gets; &lt;code&gt;/actuator/env&lt;/code&gt; shows the sources.&lt;/li&gt;
&lt;li&gt;An Actuator endpoint is available over HTTP only when access is permitted and it is exposed. &lt;code&gt;include&lt;/code&gt;, &lt;code&gt;exclude&lt;/code&gt;, global and per-endpoint access, &lt;code&gt;max-permitted&lt;/code&gt; and the management port all take part.&lt;/li&gt;
&lt;li&gt;Maps merge by key; lists are replaced whole, including lists of objects.&lt;/li&gt;
&lt;li&gt;Some ambiguous configurations don't fail silently: they stop the application from starting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The test app, the Actuator scenarios script and the expected results are in the spring-config-guard repository (&lt;code&gt;VALIDATION.md&lt;/code&gt; and &lt;code&gt;ARCHITECTURE.md&lt;/code&gt;). If you know of a configuration where Spring behaves differently from what I describe, I'd like to hear about it.&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>java</category>
      <category>security</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
