Southclaws / sampctl

The Swiss Army Knife of SA:MP - vital tools for any server owner or library maintainer.
GNU General Public License v3.0
239 stars 34 forks source link

.pawn constants values not being proxied to source files #511

Open pedropapa opened 10 months ago

pedropapa commented 10 months ago

As a sampctl user I want to be able to define constants in pawn.json So that I don't have sensitive information such as database credentials in my .pawn files.

Scenario 1: Works in code ✅

Given a constant as string in a .pwn source file. When compiling package with a ubuntu image in a docker container. Then the compiled .amx file is generated successfully.

Example

package.pwn

...
#define MYSQL_HOST  "my-mysql-db"
#define MYSQL_USER  "root"
#define MYSQL_PASS  "abcd1234"
#define MYSQL_DB    "default"
...
mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DB);
...

Scenario 2: Fails in sampctl ❌

Given a constant as string in constants configuration for a build in pawn.json. When compiling package with a ubuntu image in a docker container. Then a compiler error argument type mismatch is thrown.

Example

pawn.json

{
  "user": "pedropapa",
  "repo": "example",
  "entry": "package.pwn",
  "output": "../../filterscripts/package.amx",
  "dependencies": ["pawn-lang/samp-stdlib", "pBlueG/SA-MP-MySQL:R41-4"],
  "runtime": {
    "version": "0.3.7",
    "mode": "server",
    "rcon_password": "any",
    "port": 7777
  },
  "builds": [
    {
      "name": "main",
      "args": ["-;+", "-(+", "-O1", "-Z+", "-d3"],
      "compiler": {},
      "constants": {
        "MYSQL_HOST": "127.0.0.1",
        "MYSQL_PORT": "3306",
        "MYSQL_USER": "root",
        "MYSQL_PASS": "abcd1234",
        "MYSQL_DB": "brz"
      }
    }
  ]
}

package.pawn

...
printf("debugging mysql_connect with %s, %s, %s, %s", MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DB);
mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DB);
...

Error thrown when compiling

11.95 INFO: building pedropapa/package with 3.10.10
11.95 INFO: executing compiler in /server/packages/package as [LD_LIBRARY_PATH=/root/.config/sampctl/pawn/3.10.10 DYLD_LIBRARY_PATH=/root/.config/sampctl/pawn/3.10.10] [/root/.config/sampctl/pawn/3.10.10/pawncc /server/packages/package/package.pwn -D/server/packages/package -o/server/filterscripts/package.amx -;+ -(+ -O1 -Z+ -d3 -i/server/legacy -i/server/packages/package -i/server/packages/package/dependencies/samp-stdlib -i/server/packages/package/dependencies/pawn-stdlib -i/server/packages/package/dependencies/SA-MP-MySQL -i/server/packages/package/dependencies/.resources/SA-MP-MySQL-5f509e MYSQL_DB=brz MYSQL_HOST=127.0.0.1 MYSQL_PORT=3306 MYSQL_USER=root MYSQL_PASS=abcd1234]
12.59 /server/packages/package/package.pwn:10 (error) argument type mismatch (argument 1)

Message in console when debugging the constants values.

debugging mysql_connect with , , , 

By the message above I believe the constant values are not being passed somehow to the source code when compiling, either by a mistake on my side (which I can't see where, since the correct values are in pawn compiler args) or something funky in pawn compiler / sampctl. The constants are defined given the build passes, but with an empty value.

I also took a look in pawn's compiler options and by the looks of it I don't think there's anything wrong in sampctl's side, mainly because on how the downstream compiler command is being built, so maybe it could be some platform issue? I have an ARM mac hence I use docker to build my scripts.

ADRFranklin commented 10 months ago

Well you should instead make use of .env files which sampctl autoloads and use the pawn-env plugin https://github.com/dakyskye/pawn-env

Because pawn.json files are generally uploaded to git repositories, we don't recommend storing sensitive information such as database information within them, this is why there exists a system like .env files which are designed to not be uploaded to repositories and are generally excluded in git repos.

pedropapa commented 10 months ago

@ADRFranklin Thanks for your reply, correct, in my real codebase I don't have these constants in the pawn.json file, but rather as docker env vars, in my pawn.json I just have:

{
      "name": "main",
      "includes": ["../../legacy"],
      "args": ["-;+", "-(+", "-O1", "-Z+"],
      "compiler": {},
      "constants": {
        "MYSQL_HOST": "$MYSQL_HOST",
        "MYSQL_PORT": "$MYSQL_PORT",
        "MYSQL_USER": "$MYSQL_USER",
        "MYSQL_PASS": "$MYSQL_PASS",
        "MYSQL_DB": "$MYSQL_DB"
      }
    },

The snippet I posted was just a reproducible example of the issue with sampctl constants. To be fair I couldn't make it work using pawn compiler directly passing the constants as compiler options.

Using env variables also doesn't work. I'll check out the library you provided, cheers.

Also about having database connection configuration versioned: It actually depends on the use case right? I assume you're talking about production environment which I obviously agree, but if I have an integration tests setup on my ci workflow where the database schema is short-lived (created/destroyed during the workflow run) and only accessible from the CI tool (i.e. Github Actions), I don't see any harm or potential security issues, I would end up having something like:

{
....
  "builds": [
    {
      "name": "live",
      "includes": ["../../legacy"],
      "args": ["-;+", "-(+", "-O1", "-Z+"],
      "compiler": {},
      "constants": {
        "MYSQL_HOST": "$MYSQL_HOST",
        "MYSQL_PORT": "$MYSQL_PORT",
        "MYSQL_USER": "$MYSQL_USER",
        "MYSQL_PASS": "$MYSQL_PASS",
        "MYSQL_DB": "$MYSQL_DB"
      }
    },
    {
      "name": "tests",
      "includes": ["../../legacy"],
      "args": ["-;+", "-(+", "-O1", "-Z+", "-d3"],
      "compiler": {},
      "constants": {
        "MYSQL_HOST": "127.0.0.1",
        "MYSQL_PORT": "3306",
        "MYSQL_USER": "integration_tests",
        "MYSQL_PASS": "integration_tests",
        "MYSQL_DB": "integration_tests"
      }
    }
  ]
}
ADRFranklin commented 10 months ago

The stuff in constants are passed to the compiler using the symbol params. I use constants all the time specifically for passing the environment, so I only build specific code. Never had a problem doing this or detecting if one exists, so I am not sure what doesn't work for you?

pedropapa commented 10 months ago

@ADRFranklin I have no issues when the constant value is a number, however when it's a string it's defined as empty.

"constants": {
  "MY_CONSTANT_NUMBER": "300", // works
  "MY_CONSTANT_STRING": "test" // will output an empty string when running printf("%s", MY_CONSTANT_STRING);
},