<?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: Shmavon Gazanchyan</title>
    <description>The latest articles on DEV Community by Shmavon Gazanchyan (@mungell).</description>
    <link>https://dev.to/mungell</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F228497%2F79d671b3-fb4e-4dc2-9774-dc5228be97af.jpeg</url>
      <title>DEV Community: Shmavon Gazanchyan</title>
      <link>https://dev.to/mungell</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mungell"/>
    <language>en</language>
    <item>
      <title>SonarQube and GitLab Setup</title>
      <dc:creator>Shmavon Gazanchyan</dc:creator>
      <pubDate>Sun, 07 Jun 2020 22:39:37 +0000</pubDate>
      <link>https://dev.to/mungell/setup-sonarqube-with-gitlab-542b</link>
      <guid>https://dev.to/mungell/setup-sonarqube-with-gitlab-542b</guid>
      <description>&lt;p&gt;&lt;a href="https://www.sonarqube.org/" rel="noopener noreferrer"&gt;SonarQube&lt;/a&gt; is a great tool for code quality and security checks. It is one of the tools we use to ensure quality of our products is measured and improved over time.&lt;/p&gt;

&lt;p&gt;We also use &lt;a href="https://gitlab.com" rel="noopener noreferrer"&gt;GitLab&lt;/a&gt; – code management and CI/CD tool on some of our projects. SonarQube code analysis is integrated as a step in our GitLab CI pipelines.&lt;/p&gt;

&lt;p&gt;For a long time I had a custom-built docker image for those purposes, automatically built and published to GitLab Container Registry.&lt;/p&gt;

&lt;p&gt;Although quite automated, this custom-build docker image was adding to maintenance of the pipelines. I was happy to see that SonarSource has recently published &lt;a href="https://github.com/SonarSource/sonar-scanner-cli-docker" rel="noopener noreferrer"&gt;official SonarScanner CLI docker image&lt;/a&gt;, and &lt;a href="https://www.sonarqube.org/sonarqube-8-0/" rel="noopener noreferrer"&gt;announced a support for GitLab integration in v8&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/SonarSource" rel="noopener noreferrer"&gt;
        SonarSource
      &lt;/a&gt; / &lt;a href="https://github.com/SonarSource/sonar-scanner-cli-docker" rel="noopener noreferrer"&gt;
        sonar-scanner-cli-docker
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Docker image for SonarScanner CLI
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The docker image expects code being mounted on &lt;a href="https://github.com/SonarSource/sonar-scanner-cli-docker/blob/f210c44a7b9af1cc74939335f2f9101550592f94/4/bin/entrypoint.sh#L13" rel="noopener noreferrer"&gt;&lt;code&gt;$PWD&lt;/code&gt;&lt;/a&gt;, which is set to &lt;a href="https://github.com/SonarSource/sonar-scanner-cli-docker/blob/f210c44a7b9af1cc74939335f2f9101550592f94/4/Dockerfile#L34" rel="noopener noreferrer"&gt;&lt;code&gt;/usr/src&lt;/code&gt;&lt;/a&gt;. This is different to where GitLab is mounting sources directory by default.&lt;/p&gt;

&lt;p&gt;To make it all work the following environment variable needs to be set:&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;sonar&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sonarsource/sonar-scanner-cli&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sonar-scanner -Dsonar.qualitygate.wait=true&lt;/span&gt;
  &lt;span class="na"&gt;allow_failure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;SONAR_PROJECT_BASE_DIR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${CI_PROJECT_DIR}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Environment variable &lt;code&gt;SONAR_PROJECT_BASE_DIR&lt;/code&gt; &lt;a href="https://github.com/SonarSource/sonar-scanner-cli-docker/blob/f210c44a7b9af1cc74939335f2f9101550592f94/4/bin/entrypoint.sh#L15" rel="noopener noreferrer"&gt;overrides default behavior&lt;/a&gt;. Predefined GitLab environment variable &lt;a href="https://docs.gitlab.com/ee/ci/variables/predefined_variables.html" rel="noopener noreferrer"&gt;&lt;code&gt;CI_PROJECT_DIR&lt;/code&gt;&lt;/a&gt; refers to the location where GitLab is mounting project source code.&lt;/p&gt;

&lt;p&gt;Without this variable set the following misleading error will appear in GitLab log:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERROR: Error during SonarScanner execution
java.lang.IllegalStateException: Unable to create user cache: /usr/src/.sonar/cache
    at org.sonarsource.scanner.api.internal.cache.FileCache.createDir(FileCache.java:147)
    at org.sonarsource.scanner.api.internal.cache.FileCache.&amp;lt;init&amp;gt;(FileCache.java:46)
    at org.sonarsource.scanner.api.internal.cache.FileCache.create(FileCache.java:52)
    at org.sonarsource.scanner.api.internal.cache.FileCacheBuilder.build(FileCacheBuilder.java:48)
    at org.sonarsource.scanner.api.internal.JarDownloaderFactory.create(JarDownloaderFactory.java:42)
    at org.sonarsource.scanner.api.internal.IsolatedLauncherFactory.createLauncher(IsolatedLauncherFactory.java:68)
    at org.sonarsource.scanner.api.EmbeddedScanner.doStart(EmbeddedScanner.java:185)
    at org.sonarsource.scanner.api.EmbeddedScanner.start(EmbeddedScanner.java:123)
    at org.sonarsource.scanner.cli.Main.execute(Main.java:73)
    at org.sonarsource.scanner.cli.Main.main(Main.java:61)
Caused by: java.nio.file.AccessDeniedException: /usr/src/.sonar
    at java.base/sun.nio.fs.UnixException.translateToIOException(Unknown Source)
    at java.base/sun.nio.fs.UnixException.rethrowAsIOException(Unknown Source)
    at java.base/sun.nio.fs.UnixException.rethrowAsIOException(Unknown Source)
    at java.base/sun.nio.fs.UnixFileSystemProvider.createDirectory(Unknown Source)
    at java.base/java.nio.file.Files.createDirectory(Unknown Source)
    at java.base/java.nio.file.Files.createAndCheckIsDirectory(Unknown Source)
    at java.base/java.nio.file.Files.createDirectories(Unknown Source)
    at org.sonarsource.scanner.api.internal.cache.FileCache.createDir(FileCache.java:145)
    ... 9 more
ERROR: 
ERROR: Re-run SonarScanner using the -X switch to enable full debug logging.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Improvements
&lt;/h2&gt;

&lt;p&gt;It might be a good idea to cache Sonar Scanner directories to be re-used in future pipeline runs:&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;sonar&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sonarsource/sonar-scanner-cli&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sonar-scanner -Dsonar.qualitygate.wait=true&lt;/span&gt;
  &lt;span class="na"&gt;allow_failure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;SONAR_PROJECT_BASE_DIR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${CI_PROJECT_DIR}"&lt;/span&gt;
  &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sonar-${CI_PROJECT_ID}"&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.scannerwork"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.sonar"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my particular case, SonarQube analysis was not dependent on any other steps in the pipeline, so I've used &lt;a href="https://docs.gitlab.com/ee/ci/yaml/#needs" rel="noopener noreferrer"&gt;&lt;code&gt;needs&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://docs.gitlab.com/ee/ci/yaml/#dependencies" rel="noopener noreferrer"&gt;&lt;code&gt;dependencies&lt;/code&gt;&lt;/a&gt; properties to make it run ahead of time and skip downloading artifacts of other steps.&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;sonar&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sonarsource/sonar-scanner-cli&lt;/span&gt;
  &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
  &lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sonar-scanner -Dsonar.qualitygate.wait=true&lt;/span&gt;
  &lt;span class="na"&gt;allow_failure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;SONAR_PROJECT_BASE_DIR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${CI_PROJECT_DIR}"&lt;/span&gt;
    &lt;span class="na"&gt;GIT_DEPTH&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
  &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sonar-${CI_PROJECT_ID}"&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.scannerwork"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.sonar"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, I've used &lt;code&gt;GIT_DEPTH&lt;/code&gt; environment variable to enforce &lt;a href="https://docs.gitlab.com/ee/ci/large_repositories/" rel="noopener noreferrer"&gt;Shallow Clone&lt;/a&gt; of our fairly large repository.&lt;/p&gt;

</description>
      <category>gitlab</category>
      <category>sonarqube</category>
      <category>docker</category>
      <category>devops</category>
    </item>
    <item>
      <title>Hacktoberfest Tips</title>
      <dc:creator>Shmavon Gazanchyan</dc:creator>
      <pubDate>Wed, 02 Oct 2019 16:15:53 +0000</pubDate>
      <link>https://dev.to/mungell/hacktoberfest-tips-4n5i</link>
      <guid>https://dev.to/mungell/hacktoberfest-tips-4n5i</guid>
      <description>&lt;p&gt;October is here. For many GitHub repository maintainers (including me) it means the whole month of Pull Requests thanks to Hacktoberfest. This is the time when open source projects are getting a boost in contributions that help them develop new features, fix old bugs and attract new contributors.&lt;/p&gt;

&lt;p&gt;If you plan to participate in this festival of PRs below is a couple of tips on how to make a good contribution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read the contributing guidelines
&lt;/h2&gt;

&lt;p&gt;Many repositories will have a &lt;code&gt;CONTRIBUTING.md&lt;/code&gt; file that contains important information on project code style, PR review workflow, test coverage requirements, and other contributing guidelines.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: the actual file name may vary: &lt;code&gt;CONTRIBUTING&lt;/code&gt;, &lt;code&gt;CONTRIBUTE&lt;/code&gt;, with or without &lt;code&gt;.md&lt;/code&gt; extension, could be written in lowercase as well.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you are struggling to find this document in the repository, GitHub has a convenient link to the file on Pull Requests page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ec5YzMuL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/jhyn6iah4p3vakiijaz6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ec5YzMuL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/jhyn6iah4p3vakiijaz6.png" alt="GitHub contributing link"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Give a clear description of your pull request
&lt;/h2&gt;

&lt;p&gt;Help the maintainer quickly understand what problem your PR is solving. If there is an existing Issue on GitHub – reference it in the Pull Request description to give some more context.&lt;/p&gt;

&lt;p&gt;This could be a very valuable contribution, but it is hard to say from the name or (absence of) description in the PR:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TgruHD8C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/gu9zxg1eg2wqskf2mob1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TgruHD8C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/gu9zxg1eg2wqskf2mob1.png" alt="No description example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a good example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aofgdKFc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/0d2pz5tschcpm5cqcqrb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aofgdKFc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/0d2pz5tschcpm5cqcqrb.png" alt="Good example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Match code style of the rest of the code
&lt;/h2&gt;

&lt;p&gt;This is simple but often forgotten advice. Each project has its own code style and standards. When contributing to a project, make sure your code is following the same standards even if you don't agree with them.&lt;/p&gt;

&lt;p&gt;If a project is using tabs for code indentation and you are a radical 4-space evangelist, when contributing to this project you are expected to follow their code style (yes, tabs) even if it is not mentioned in their contributing guidelines.&lt;/p&gt;

&lt;p&gt;Code style guidelines are designed to make code look consistent – it greatly improves its readability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Follow Pull Request template if it exists
&lt;/h2&gt;

&lt;p&gt;GitHub provides a nice feature that allows maintainers to set a template for new Pull Requests. If the project you contributing to has such a template - read it carefully and follow steps described in it before submitting your PR.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vXZKg1r4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ut8ulhjqt5u9v8g6w1kk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vXZKg1r4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ut8ulhjqt5u9v8g6w1kk.png" alt="PR template example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't give up if maintainers do not respond instantly
&lt;/h2&gt;

&lt;p&gt;Maintainers could be slow in response - unfortunately, it happens (I am guilty of this myself). Hacktoberfest is a busy period for all maintainers, so leave your PR open and move on - they will get back to you, just a little bit later.&lt;/p&gt;

</description>
      <category>hacktoberfest</category>
      <category>github</category>
      <category>opensource</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Google Cloud App Engine Environment Variables</title>
      <dc:creator>Shmavon Gazanchyan</dc:creator>
      <pubDate>Tue, 17 Sep 2019 16:41:50 +0000</pubDate>
      <link>https://dev.to/mungell/google-cloud-app-engine-environment-variables-5990</link>
      <guid>https://dev.to/mungell/google-cloud-app-engine-environment-variables-5990</guid>
      <description>&lt;p&gt;One of my recent projects involved an application that had to be hosted on  Google Cloud App Engine. I didn't use App Engine before, but I've managed apps on Heroku and OpenShift and was interested to see what Google Cloud PaaS had to offer.&lt;/p&gt;

&lt;p&gt;It was a fairly standard Node.js application with most of the configuration done with environment variables. Soon it became clear that this could be a problem – App Engine does not support configurable environment variables.&lt;/p&gt;

&lt;p&gt;Intentional or not, App Engine has only one way of defining those variables – in &lt;a href="https://cloud.google.com/appengine/docs/standard/nodejs/config/appref" rel="noopener noreferrer"&gt;&lt;code&gt;app.yaml&lt;/code&gt;&lt;/a&gt; configuration file. This file describes App Engine settings (runtime, url mappings etc.), including &lt;code&gt;env_variables&lt;/code&gt; section that instructs App Engine to set environment variables on deployment.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example &lt;code&gt;app.yaml&lt;/code&gt; file content:&lt;/em&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;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nodejs10&lt;/span&gt;

&lt;span class="na"&gt;handlers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/api/.*&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;auto&lt;/span&gt;
  &lt;span class="na"&gt;secure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/.*&lt;/span&gt;
  &lt;span class="na"&gt;static_files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;index.html&lt;/span&gt;
  &lt;span class="na"&gt;upload&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;index.html&lt;/span&gt;
  &lt;span class="na"&gt;secure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
  &lt;span class="na"&gt;http_headers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;X-Frame-Options&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deny&lt;/span&gt;
    &lt;span class="na"&gt;X-DNS-Prefetch-Control&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;off&lt;/span&gt;
    &lt;span class="na"&gt;X-XSS-Protection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1; mode=block&lt;/span&gt;
    &lt;span class="na"&gt;X-Permitted-Cross-Domain-Policies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;none&lt;/span&gt;

&lt;span class="na"&gt;env_variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;VAR1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;VALUE1'&lt;/span&gt;
    &lt;span class="na"&gt;VAR2&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;VALUE2'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Our deployment pipeline was already fully automated, so I needed to store &lt;code&gt;app.yaml&lt;/code&gt; file somewhere to supply it to build server before pushing code to Google Cloud. Ideally, it would be application's code repository. However, having environment variables in &lt;code&gt;app.yaml&lt;/code&gt; file caused an issue: we either needed to commit application configuration to the repository, or leave the whole file untracked. Neither of these options was suitable, so I started looking for any other ways of dealing with this App Engine limitation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As a side note, Heroku and OpenShift (at least its previous incarnation) have an option to set environment variables from the web/command line interface, which simplified application configuration management. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My search brought me some disappointing results:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Store application configuration in the Google Cloud Datastore and read from it on application startup (&lt;a href="https://stackoverflow.com/questions/22669528/securely-storing-environment-variables-in-gae-with-app-yaml" rel="noopener noreferrer"&gt;link&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Encrypt configuration values with Cloud KMS and commit together with the rest of the &lt;code&gt;app.yaml&lt;/code&gt; configuration (&lt;a href="https://news.ycombinator.com/item?id=18231319" rel="noopener noreferrer"&gt;link&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Use separate &lt;code&gt;app.yaml&lt;/code&gt; files for different environments (and, I guess, commit them all to the repository?) (&lt;a href="https://news.ycombinator.com/item?id=18231319" rel="noopener noreferrer"&gt;same link&lt;/a&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fadf7b37bxwn1tvkx1ihg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fadf7b37bxwn1tvkx1ihg.png" alt="Hacker News Discussion"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option #1&lt;/strong&gt; assumed additional component in our infrastructure and vendor lock-in to Google Cloud Datastore database, which was far from ideal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option #2&lt;/strong&gt; solved the security part of the problem, but would mean hardcoding encrypted environment-specific values to the codebase. It would also require to update the code with each new environment added or any changes to the existing environment variables. Not ideal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option #3&lt;/strong&gt; didn't solve he problem at all – code would still store information about its environments and application secrets will be available right in the code repository...&lt;/p&gt;

&lt;h3&gt;
  
  
  Extra step in deployment pipeline
&lt;/h3&gt;

&lt;p&gt;Eventually, I've came up with an approach that involved compiling &lt;code&gt;app.yaml&lt;/code&gt; file from template file during the build process. At that moment we used Google Cloud Build as a build server for CI/CD, but quickly moved to GitLab CI &lt;em&gt;since Cloud Build does not support environment variables either&lt;/em&gt;. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To be fair, I should mention that Cloud Build supports &lt;a href="https://cloud.google.com/cloud-build/docs/configuring-builds/substitute-variable-values" rel="noopener noreferrer"&gt;"substitutions"&lt;/a&gt;, which are remotely similar to environment variables. Unfortunately, the only way to pass substitutions to the build job is through command line arguments, which means managing environment variables somewhere outside. And this brings us back to the original problem...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The application was already using EJS library, so I used it to compile the template:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="c1"&gt;# app.tpl.yaml&lt;/span&gt;
&lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nodejs10&lt;/span&gt;
&lt;span class="na"&gt;env_variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;SSO_CLIENT_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;% SSO_CLIENT_ID %&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;SSO_SECRET&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;% SSO_SECRET %&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;with a script like that:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// bin/config-compile.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ejs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ejs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app.tpl.yaml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ejs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app.yaml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;and GitLab CI step similar to this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="c1"&gt;# .gitlab-ci.yml&lt;/span&gt;
&lt;span class="na"&gt;config-compile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node:10&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node bin/config-compile.js&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;app.yaml&lt;/span&gt;
    &lt;span class="na"&gt;expire_in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1 days&lt;/span&gt;
    &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This enabled us to manage application configuration in GitLab environment variables.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ffecafmgbm8d31k39220x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ffecafmgbm8d31k39220x.png" alt="GitLab CI Variables Interface"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The approach can easily be adapted to any other templating library, programming language or build server, the code above is just an example.&lt;/p&gt;

&lt;h3&gt;
  
  
  A note on security
&lt;/h3&gt;

&lt;p&gt;I found it interesting that one of the oldest Google Cloud products doesn't support such a common functionality. However, I accept there could be valid security reasons for doing so, e.g. exposure to dependency vulnerability similar to the one discovered in &lt;a href="https://github.com/rest-client/rest-client/issues/713#issuecomment-522967049" rel="noopener noreferrer"&gt;rest-client&lt;/a&gt; or typo-squatting like &lt;a href="https://blog.npmjs.org/post/163723642530/crossenv-malware-on-the-npm-registry" rel="noopener noreferrer"&gt;in npm registry&lt;/a&gt;. This is especially relevant as App Engine does not provide options to limit/manage outgoing connections from the environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Alternative solutions not covered in this post
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.dontpanicblog.co.uk/2019/04/27/secrets-in-google-app-engine/" rel="noopener noreferrer"&gt;"Secrets in Google App Engine"&lt;/a&gt; by Stuart Leitch&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://medium.com/@gunar/how-to-use-environment-variables-in-gcloud-app-engine-node-js-86623b3ab0f6" rel="noopener noreferrer"&gt;"How to use Environment Variables in GCloud App Engine"&lt;/a&gt; by Gunar Gessner&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>gcp</category>
      <category>cloud</category>
      <category>appengine</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
