accept_env_test.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package tailssh
  4. import (
  5. "fmt"
  6. "testing"
  7. "github.com/google/go-cmp/cmp"
  8. )
  9. func TestMatchAcceptEnvPattern(t *testing.T) {
  10. testCases := []struct {
  11. pattern string
  12. target string
  13. match bool
  14. }{
  15. {pattern: "*", target: "EXAMPLE_ENV", match: true},
  16. {pattern: "***", target: "123456", match: true},
  17. {pattern: "?", target: "A", match: true},
  18. {pattern: "?", target: "123", match: false},
  19. {pattern: "?*", target: "EXAMPLE_2", match: true},
  20. {pattern: "?*", target: "", match: false},
  21. {pattern: "*?", target: "A", match: true},
  22. {pattern: "*?", target: "", match: false},
  23. {pattern: "??", target: "CC", match: true},
  24. {pattern: "??", target: "123", match: false},
  25. {pattern: "*?*", target: "ABCDEFG", match: true},
  26. {pattern: "*?*", target: "C", match: true},
  27. {pattern: "*?*", target: "", match: false},
  28. {pattern: "?*?", target: "ABCDEFG", match: true},
  29. {pattern: "?*?", target: "A", match: false},
  30. {pattern: "**?TEST", target: "_TEST", match: true},
  31. {pattern: "**?TEST", target: "_TESTING", match: false},
  32. {pattern: "TEST**?", target: "TEST_", match: true},
  33. {pattern: "TEST**?", target: "A_TEST_", match: false},
  34. {pattern: "TEST_*", target: "TEST_A", match: true},
  35. {pattern: "TEST_*", target: "TEST_A_LONG_ENVIRONMENT_VARIABLE_NAME", match: true},
  36. {pattern: "TEST_*", target: "TEST", match: false},
  37. {pattern: "EXAMPLE_?_ENV", target: "EXAMPLE_A_ENV", match: true},
  38. {pattern: "EXAMPLE_?_ENV", target: "EXAMPLE_ENV", match: false},
  39. {pattern: "EXAMPLE_*_ENV", target: "EXAMPLE_aBcd2231---_ENV", match: true},
  40. {pattern: "EXAMPLE_*_ENV", target: "EXAMPLEENV", match: false},
  41. {pattern: "COMPLICA?ED_PATTERN*", target: "COMPLICATED_PATTERN_REST", match: true},
  42. {pattern: "COMPLICA?ED_PATTERN*", target: "COMPLICATED_PATT", match: false},
  43. {pattern: "COMPLICAT???ED_PATT??ERN", target: "COMPLICAT123ED_PATTggERN", match: true},
  44. {pattern: "COMPLICAT???ED_PATT??ERN", target: "COMPLICATED_PATTERN", match: false},
  45. {pattern: "DIRECT_MATCH", target: "DIRECT_MATCH", match: true},
  46. {pattern: "DIRECT_MATCH", target: "MISS", match: false},
  47. // OpenSSH compatibility cases
  48. // See https://github.com/openssh/openssh-portable/blob/master/regress/unittests/match/tests.c
  49. {pattern: "", target: "", match: true},
  50. {pattern: "aaa", target: "", match: false},
  51. {pattern: "", target: "aaa", match: false},
  52. {pattern: "aaaa", target: "aaa", match: false},
  53. {pattern: "aaa", target: "aaaa", match: false},
  54. {pattern: "*", target: "", match: true},
  55. {pattern: "?", target: "a", match: true},
  56. {pattern: "a?", target: "aa", match: true},
  57. {pattern: "*", target: "a", match: true},
  58. {pattern: "a*", target: "aa", match: true},
  59. {pattern: "?*", target: "aa", match: true},
  60. {pattern: "**", target: "aa", match: true},
  61. {pattern: "?a", target: "aa", match: true},
  62. {pattern: "*a", target: "aa", match: true},
  63. {pattern: "a?", target: "ba", match: false},
  64. {pattern: "a*", target: "ba", match: false},
  65. {pattern: "?a", target: "ab", match: false},
  66. {pattern: "*a", target: "ab", match: false},
  67. }
  68. for _, tc := range testCases {
  69. name := fmt.Sprintf("pattern_%s_target_%s", tc.pattern, tc.target)
  70. if tc.match {
  71. name += "_should_match"
  72. } else {
  73. name += "_should_not_match"
  74. }
  75. t.Run(name, func(t *testing.T) {
  76. match := matchAcceptEnvPattern(tc.pattern, tc.target)
  77. if match != tc.match {
  78. t.Errorf("got %v, want %v", match, tc.match)
  79. }
  80. })
  81. }
  82. }
  83. func TestFilterEnv(t *testing.T) {
  84. testCases := []struct {
  85. name string
  86. acceptEnv []string
  87. environ []string
  88. expectedFiltered []string
  89. wantErrMessage string
  90. }{
  91. {
  92. name: "simple direct matches",
  93. acceptEnv: []string{"FOO", "FOO2", "FOO_3"},
  94. environ: []string{"FOO=BAR", "FOO2=BAZ", "FOO_3=123", "FOOOO4-2=AbCdEfG"},
  95. expectedFiltered: []string{"FOO=BAR", "FOO2=BAZ", "FOO_3=123"},
  96. },
  97. {
  98. name: "bare wildcard",
  99. acceptEnv: []string{"*"},
  100. environ: []string{"FOO=BAR", "FOO2=BAZ", "FOO_3=123", "FOOOO4-2=AbCdEfG"},
  101. expectedFiltered: []string{"FOO=BAR", "FOO2=BAZ", "FOO_3=123", "FOOOO4-2=AbCdEfG"},
  102. },
  103. {
  104. name: "complex matches",
  105. acceptEnv: []string{"FO?", "FOOO*", "FO*5?7"},
  106. environ: []string{"FOO=BAR", "FOO2=BAZ", "FOO_3=123", "FOOOO4-2=AbCdEfG", "FO1-kmndGamc79567=ABC", "FO57=BAR2"},
  107. expectedFiltered: []string{"FOO=BAR", "FOOOO4-2=AbCdEfG", "FO1-kmndGamc79567=ABC"},
  108. },
  109. {
  110. name: "environ format invalid",
  111. acceptEnv: []string{"FO?", "FOOO*", "FO*5?7"},
  112. environ: []string{"FOOBAR"},
  113. expectedFiltered: nil,
  114. wantErrMessage: `invalid environment variable: "FOOBAR". Variables must be in "KEY=VALUE" format`,
  115. },
  116. }
  117. for _, tc := range testCases {
  118. t.Run(tc.name, func(t *testing.T) {
  119. filtered, err := filterEnv(tc.acceptEnv, tc.environ)
  120. if err == nil && tc.wantErrMessage != "" {
  121. t.Errorf("wanted error with message %q but error was nil", tc.wantErrMessage)
  122. }
  123. if err != nil && err.Error() != tc.wantErrMessage {
  124. t.Errorf("err = %v; want %v", err, tc.wantErrMessage)
  125. }
  126. if diff := cmp.Diff(tc.expectedFiltered, filtered); diff != "" {
  127. t.Errorf("unexpected filter result (-got,+want): \n%s", diff)
  128. }
  129. })
  130. }
  131. }