Skip to content

Commit d36d7e6

Browse files
authored
validate-hook - add envars-validate hook (#33)
Description: Added envars-validate pre-commit-hook to run the validate command off the repository, to support our other pre-commit stacks Ticket: tops-1718 Testing: Used via the personal test repository targetting branch
1 parent ab5d80d commit d36d7e6

2 files changed

Lines changed: 296 additions & 0 deletions

File tree

.pre-commit-hooks.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
- id: envars-validate
2+
name: Validate envars configuration
3+
description: Validates envars.yml file
4+
entry: envars
5+
language: python
6+
args: [validate]
7+
files: ^envars\.yml$
8+
require_serial: true
9+
additional_dependencies: []
10+
pass_filenames: false

tests/test_cli.py

Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,3 +479,289 @@ def test_var_from_env(tmp_path):
479479
os.environ["RELEASE_SHA"] = '12345'
480480
ret = envars.process(args)
481481
assert ret == ['TEST=12345']
482+
483+
484+
def test_validate_success(tmp_path):
485+
"""test valid configuration is successful"""
486+
run_cmd(tmp_path, 'init --app testapp --environments prod,staging --kms-key-arn abc')
487+
run_cmd(tmp_path, 'add TEST_VAR=test')
488+
run_cmd(tmp_path, 'add -e prod PROD_VAR=prod-value')
489+
run_cmd(tmp_path, 'add -e staging -a master STAGING_VAR=staging-master')
490+
491+
ret = run_cmd(tmp_path, 'validate')
492+
assert ret.returncode == 0
493+
494+
495+
def test_validate_lowercase_var_fails(tmp_path):
496+
"""test lowercase variable names"""
497+
run_cmd(tmp_path, 'init --app testapp --environments prod,staging --kms-key-arn abc')
498+
499+
with open(f'{tmp_path}/envars.yml', 'w') as f:
500+
f.write("""configuration:
501+
APP: testapp
502+
ENVIRONMENTS:
503+
- prod
504+
- staging
505+
KMS_KEY_ARN: abc
506+
507+
environment_variables:
508+
test_var:
509+
default: value
510+
""")
511+
512+
ret = subprocess.run(
513+
f'{CMD} -f {tmp_path}/envars.yml validate',
514+
shell=True,
515+
capture_output=True,
516+
text=True
517+
)
518+
assert ret.returncode == 1
519+
assert 'var name "test_var" is not uppercase' in ret.stdout
520+
521+
522+
def test_validate_mixed_case_var_fails(tmp_path):
523+
"""test mixed case variable names"""
524+
run_cmd(tmp_path, 'init --app testapp --environments prod,staging --kms-key-arn abc')
525+
526+
with open(f'{tmp_path}/envars.yml', 'w') as f:
527+
f.write("""configuration:
528+
APP: testapp
529+
ENVIRONMENTS:
530+
- prod
531+
- staging
532+
KMS_KEY_ARN: abc
533+
534+
environment_variables:
535+
TestVar:
536+
default: value
537+
""")
538+
539+
ret = subprocess.run(
540+
f'{CMD} -f {tmp_path}/envars.yml validate',
541+
shell=True,
542+
capture_output=True,
543+
text=True
544+
)
545+
assert ret.returncode == 1
546+
assert 'var name "TestVar" is not uppercase' in ret.stdout
547+
548+
549+
def test_validate_unknown_env_fails(tmp_path):
550+
"""test unkown environment fails validation"""
551+
run_cmd(tmp_path, 'init --app testapp --environments prod,staging --kms-key-arn abc')
552+
553+
with open(f'{tmp_path}/envars.yml', 'w') as f:
554+
f.write("""configuration:
555+
APP: testapp
556+
ENVIRONMENTS:
557+
- prod
558+
- staging
559+
KMS_KEY_ARN: abc
560+
561+
environment_variables:
562+
TEST_VAR:
563+
default: value
564+
development: dev-value
565+
""")
566+
567+
ret = subprocess.run(
568+
f'{CMD} -f {tmp_path}/envars.yml validate',
569+
shell=True,
570+
capture_output=True,
571+
text=True
572+
)
573+
assert ret.returncode == 1
574+
assert '"TEST_VAR" has unknown env "development"' in ret.stdout
575+
576+
577+
def test_validate_empty_string_fails(tmp_path):
578+
"""test empty string validation failure"""
579+
run_cmd(tmp_path, 'init --app testapp --environments prod,staging --kms-key-arn abc')
580+
581+
with open(f'{tmp_path}/envars.yml', 'w') as f:
582+
f.write("""configuration:
583+
APP: testapp
584+
ENVIRONMENTS:
585+
- prod
586+
- staging
587+
KMS_KEY_ARN: abc
588+
589+
environment_variables:
590+
TEST_VAR:
591+
default: ""
592+
""")
593+
594+
ret = subprocess.run(
595+
f'{CMD} -f {tmp_path}/envars.yml validate',
596+
shell=True,
597+
capture_output=True,
598+
text=True
599+
)
600+
assert ret.returncode == 1
601+
assert '"TEST_VAR" "default" has unsupported empty string' in ret.stdout
602+
603+
604+
def test_validate_empty_string_in_account_fails(tmp_path):
605+
"""test account specific configs with empty strings"""
606+
run_cmd(tmp_path, 'init --app testapp --environments prod,staging --kms-key-arn abc')
607+
608+
with open(f'{tmp_path}/envars.yml', 'w') as f:
609+
f.write("""configuration:
610+
APP: testapp
611+
ENVIRONMENTS:
612+
- prod
613+
- staging
614+
KMS_KEY_ARN: abc
615+
616+
environment_variables:
617+
TEST_VAR:
618+
prod:
619+
master: ""
620+
""")
621+
622+
ret = subprocess.run(
623+
f'{CMD} -f {tmp_path}/envars.yml validate',
624+
shell=True,
625+
capture_output=True,
626+
text=True
627+
)
628+
assert ret.returncode == 1
629+
assert '"TEST_VAR" "prod" "master" has unsupported empty string' in ret.stdout
630+
631+
632+
def test_validate_invalid_account_fails(tmp_path):
633+
"""test invalid account names"""
634+
run_cmd(tmp_path, 'init --app testapp --environments prod,staging --kms-key-arn abc')
635+
636+
with open(f'{tmp_path}/envars.yml', 'w') as f:
637+
f.write("""configuration:
638+
APP: testapp
639+
ENVIRONMENTS:
640+
- prod
641+
- staging
642+
KMS_KEY_ARN: abc
643+
644+
environment_variables:
645+
TEST_VAR:
646+
prod:
647+
production: prod-value
648+
""")
649+
650+
ret = subprocess.run(
651+
f'{CMD} -f {tmp_path}/envars.yml validate',
652+
shell=True,
653+
capture_output=True,
654+
text=True
655+
)
656+
assert ret.returncode == 1
657+
assert '"TEST_VAR" "prod" has invalid account "production"' in ret.stdout
658+
659+
660+
def test_validate_multiple_errors(tmp_path):
661+
"""Test if we get multiple validation reports"""
662+
run_cmd(tmp_path, 'init --app testapp --environments prod,staging --kms-key-arn abc')
663+
664+
with open(f'{tmp_path}/envars.yml', 'w') as f:
665+
f.write("""configuration:
666+
APP: testapp
667+
ENVIRONMENTS:
668+
- prod
669+
- staging
670+
KMS_KEY_ARN: abc
671+
672+
environment_variables:
673+
test_var:
674+
default: value
675+
VALID_VAR:
676+
default: valid
677+
invalid_env: value
678+
ANOTHER_VAR:
679+
prod:
680+
invalid_account: value
681+
""")
682+
683+
ret = subprocess.run(
684+
f'{CMD} -f {tmp_path}/envars.yml validate',
685+
shell=True,
686+
capture_output=True,
687+
text=True
688+
)
689+
assert ret.returncode == 1
690+
assert 'var name "test_var" is not uppercase' in ret.stdout
691+
assert '"VALID_VAR" has unknown env "invalid_env"' in ret.stdout
692+
assert '"ANOTHER_VAR" "prod" has invalid account "invalid_account"' in ret.stdout
693+
694+
695+
def test_validate_with_description(tmp_path):
696+
"""test valid description field"""
697+
run_cmd(tmp_path, 'init --app testapp --environments prod,staging --kms-key-arn abc')
698+
699+
with open(f'{tmp_path}/envars.yml', 'w') as f:
700+
f.write("""configuration:
701+
APP: testapp
702+
ENVIRONMENTS:
703+
- prod
704+
- staging
705+
KMS_KEY_ARN: abc
706+
707+
environment_variables:
708+
TEST_VAR:
709+
default: value
710+
description: This is a test variable
711+
""")
712+
713+
ret = run_cmd(tmp_path, 'validate')
714+
assert ret.returncode == 0
715+
716+
717+
def test_validate_complex_valid_config(tmp_path):
718+
"""test validation with a more complex file"""
719+
run_cmd(tmp_path, 'init --app testapp --environments prod,staging,dev --kms-key-arn abc')
720+
721+
with open(f'{tmp_path}/envars.yml', 'w') as f:
722+
f.write("""configuration:
723+
APP: testapp
724+
ENVIRONMENTS:
725+
- prod
726+
- staging
727+
- dev
728+
KMS_KEY_ARN: abc
729+
730+
environment_variables:
731+
API_KEY:
732+
default: default-key
733+
description: API key for external service
734+
735+
DATABASE_URL:
736+
dev: dev-db-url
737+
staging: staging-db-url
738+
prod:
739+
master: prod-master-db-url
740+
sandbox: prod-sandbox-db-url
741+
742+
FEATURE_FLAG_1:
743+
default: "false"
744+
prod: "true"
745+
746+
MULTI_ACCOUNT_VAR:
747+
default:
748+
master: default-master
749+
sandbox: default-sandbox
750+
staging:
751+
master: staging-master
752+
sandbox: staging-sandbox
753+
""")
754+
755+
ret = run_cmd(tmp_path, 'validate')
756+
assert ret.returncode == 0
757+
758+
759+
def test_validate_nonexistent_file(tmp_path):
760+
"""Test validation fails gracefully when file doesn't exist"""
761+
ret = subprocess.run(
762+
f'{CMD} -f {tmp_path}/nonexistent.yml validate',
763+
shell=True,
764+
capture_output=True,
765+
text=True
766+
)
767+
assert ret.returncode == 1

0 commit comments

Comments
 (0)