Using secrets for code and database credentials

Hi there

I am currently working with colleagues on a small webapp that is based on PHP and a database.

We have set up a workflow where every push to the master branch copies the repository to our test webserver.

Until now we have always worked with ZIP files and email - now that is automated and simplified but now we fail because the secrets do not work as we want them to.

We don’t want to store the real database accesses, but rather a variable that is replaced by the real credential when it is delivered to the web server, so that the web server gets a running webapp while there is no critical data in the repository.

Is there a way to automate this or do we have to upload manually again?

Thank you very much in advance!

1 Like

That’s what GitHub secrets are, aren’t they?

Yes exactly. I use them always for the Action / Deploy process to store my FTP credentials in it. But now i have a repository cotaining a php file with credentials for my database and i dont want to expose them. I hoped that there is a way to hide them with with secrets.

idea; can I create a file via cat ${{ SECRET }} > file.php in the workflow? If so, I would have the file containing the access data created by the workflow…?

I haven’t tested it personally, but the documentation describes how to commit an encrypted file and decrypt it using a secret. Maybe that would help?

Having any sort of credentials hardcoded in a PHP file sounds like a bad idea. Why don’t you you let PHP read the credentials from environment variables for instance?

1 Like

Can you be more specific? I know there is such a thing, but I don’t think I’ve really worked with it.

Something along the following, with the database password stored as GitHub secret with name SCRIPT_CREDENTIALS:

  - name: Execute script
    run: php script.php


$servername = "localhost";
$username = "username";
$password = getenv("PASSWORD");

$conn = new mysqli($servername, $username, $password);

if ($conn->connect_error) {
  die("Connection failed: " . $conn->connect_error);
echo "Connected successfully";

Sorry, I was on the road for a few days and could not test nor answer anything.

Your solution looks good, would do that.

In the converted file on the server you will only find the variables but not the modified data (the content of the variables)

Run php config/db.php
  php config/db.php
  shell: /bin/bash -e {0}
    SERVER: ***
    USERNAME: ***
    PASSWORD: ***
PHP Warning:  mysqli::__construct(): (HY000/2002): No such file or directory in /home/runner/work/dcd-test/dcd-test/config/db.php on line 6
PHP Stack trace:
PHP   1. {main}() /home/runner/work/dcd-test/dcd-test/config/db.php:0
PHP   2. mysqli->__construct() /home/runner/work/dcd-test/dcd-test/config/db.php:6
Connection failed: No such file or directory

The folder is in the correct path on the server, it just seems like the php command doesn’t work. Does that need a special package?

Can you check what the working directory is with pwd?

Looks like it cannot find config/db.php relative to the current working directory. Although the last log entry says “Connection failed”, which seems a bit odd.

Thanks a lot for this!. I want to do the same using python and email credentials, instead. In python I’m using os.environ.get() to read the secrets, but with no success so far. Any ideas on how to do it with python?

To quote from your Stackoverflow post:

- name: execute py script # run to get the latest data
  env: | 

The problem is that you’re turning setting a text block for env, instead of individual keys. Correct version:

- name: execute py script # run to get the latest data

I also highly recommend moving the pip install to a separate, previous step so it doesn’t have access to the secrets. Principle of least privilege and all that.

1 Like

Thank you, it worked!. And thank you for the recommendation to move pip install to a previous step. For others interested in using secrets inside python, I can confirm that os.environ.get() does the job.

1 Like

.py file

import smtplib
import os
from email.message import EmailMessage
msg = EmailMessage()
msg[‘Subject’] = ‘Checking smtplib FROM GITHUB’
msg[‘From’] = EMAIL_ADDRESS
msg[‘To’] = ‘’
msg.set_content(‘This is a email check.’)
with smtplib.SMTP_SSL(‘’, 465) as smtp:

.yml file

  • name: execute py script

can only concatenate str (not “bytes”) to str

Please help me solve this problem

Are you using Python 2?
os.environ['...'].decode('utf8') might do the trick.

There was an issue with the GitHub secrets, was setting secrets in environment instead of repo.
@canovasjm helped me solve it.
Thank you @Simran-B @canovasjm

I am trying to use the above approach in a flutter web app with no success,
Currently I have a secret key hardcoded in my app in a *.dart file
Is it possible to access the github secrets directly in the code?
e.g I have

final secret = "*******";

can I replace it with

final secret =${{secrets.myKey }}

No, because your code isn’t processed by the workflow parser. In general it’s better to read the secret value from an environment variable or configuration file at runtime. Your workflow can then set that environment variable from a secret, or write the configuration file before calling your application.


Thanks for the reply
I am not much familiar with these scripts

- name: execute py script # run to get the latest data

Does the env file has to be already present or will it get created with the content?

and what should the run key do I did not specify the run key and the test failed with an error

every step must define a `uses` or `run` key```

The run key defines the command to run. Based the comment in your example it should probably look similar to this:

- name: execute py script
  run: python3

What you define in env will be available to the script as environment variables, not in a file. For accessing environment variables in Python, see os.environ.