github.com/kbehouse/nsc@v0.0.6/cmd/pull_test.go (about)

     1  /*
     2   * Copyright 2018-2021 The NATS Authors
     3   * Licensed under the Apache License, Version 2.0 (the "License");
     4   * you may not use this file except in compliance with the License.
     5   * You may obtain a copy of the License at
     6   *
     7   * http://www.apache.org/licenses/LICENSE-2.0
     8   *
     9   * Unless required by applicable law or agreed to in writing, software
    10   * distributed under the License is distributed on an "AS IS" BASIS,
    11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12   * See the License for the specific language governing permissions and
    13   * limitations under the License.
    14   */
    15  
    16  package cmd
    17  
    18  import (
    19  	"bytes"
    20  	"fmt"
    21  	"io/ioutil"
    22  	"os"
    23  	"path/filepath"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/nats-io/jwt/v2"
    28  	"github.com/nats-io/nkeys"
    29  	"github.com/stretchr/testify/require"
    30  )
    31  
    32  func editAccount(t *testing.T, kp nkeys.KeyPair, d []byte, tag string) []byte {
    33  	ac, err := jwt.DecodeAccountClaims(string(d))
    34  	require.NoError(t, err)
    35  	ac.Tags.Add(tag)
    36  	token, err := ac.Encode(kp)
    37  	require.NoError(t, err)
    38  	return []byte(token)
    39  }
    40  
    41  func Test_SyncAccount(t *testing.T) {
    42  	// run a jwt account server
    43  	as, m := RunTestAccountServer(t)
    44  	defer as.Close()
    45  
    46  	ts := NewTestStoreWithOperatorJWT(t, string(m["operator"]))
    47  	defer ts.Done(t)
    48  
    49  	ts.AddAccount(t, "A")
    50  	kp := ts.GetAccountKey(t, "A")
    51  	pk, err := kp.PublicKey()
    52  	require.NoError(t, err)
    53  
    54  	d := editAccount(t, kp, m[pk], "test")
    55  	m[pk] = d
    56  
    57  	_, _, err = ExecuteCmd(createPullCmd())
    58  	require.NoError(t, err)
    59  
    60  	ac, err := ts.Store.ReadAccountClaim("A")
    61  	require.NoError(t, err)
    62  	require.Contains(t, ac.Tags, "test")
    63  }
    64  
    65  func Test_SyncMultipleAccount(t *testing.T) {
    66  	as, m := RunTestAccountServer(t)
    67  	defer as.Close()
    68  
    69  	ts := NewTestStoreWithOperatorJWT(t, string(m["operator"]))
    70  	defer ts.Done(t)
    71  
    72  	ts.AddAccount(t, "A")
    73  	kp := ts.GetAccountKey(t, "A")
    74  	pk, err := kp.PublicKey()
    75  	require.NoError(t, err)
    76  	d := editAccount(t, kp, m[pk], "test")
    77  	m[pk] = d
    78  
    79  	ts.AddAccount(t, "B")
    80  	kp = ts.GetAccountKey(t, "B")
    81  	pk, err = kp.PublicKey()
    82  	require.NoError(t, err)
    83  	d = editAccount(t, kp, m[pk], "test")
    84  	m[pk] = d
    85  
    86  	_, _, err = ExecuteCmd(createPullCmd(), "--all")
    87  	require.NoError(t, err)
    88  
    89  	ac, err := ts.Store.ReadAccountClaim("A")
    90  	require.NoError(t, err)
    91  	require.Contains(t, ac.Tags, "test")
    92  
    93  	ac, err = ts.Store.ReadAccountClaim("B")
    94  	require.NoError(t, err)
    95  	require.Contains(t, ac.Tags, "test")
    96  }
    97  
    98  func Test_SyncNoAccountServer(t *testing.T) {
    99  	ts := NewTestStore(t, "O")
   100  	ts.AddAccount(t, "A")
   101  
   102  	_, _, err := ExecuteCmd(createPullCmd())
   103  	require.Error(t, err)
   104  }
   105  
   106  func Test_SyncNewer(t *testing.T) {
   107  	as, m := RunTestAccountServer(t)
   108  	defer as.Close()
   109  
   110  	ts := NewTestStoreWithOperatorJWT(t, string(m["operator"]))
   111  	defer ts.Done(t)
   112  
   113  	ts.AddAccount(t, "A")
   114  	kp := ts.GetAccountKey(t, "A")
   115  	pk, err := kp.PublicKey()
   116  	require.NoError(t, err)
   117  	time.Sleep(time.Second * 2)
   118  	// the client is supposed to update the remote server
   119  	// so this is really just an edge case - we save a newer
   120  	// one than the server has to create the issue
   121  	err = ts.Store.StoreRaw(editAccount(t, kp, m[pk], "test"))
   122  	require.NoError(t, err)
   123  	ac, err := ts.Store.ReadAccountClaim("A")
   124  	require.NoError(t, err)
   125  	require.Contains(t, ac.Tags, "test")
   126  
   127  	_, _, err = ExecuteCmd(createPullCmd())
   128  	require.Error(t, err)
   129  
   130  	ac, err = ts.Store.ReadAccountClaim("A")
   131  	require.NoError(t, err)
   132  	require.Contains(t, ac.Tags, "test")
   133  
   134  	// now allow the overwrite
   135  	_, _, err = ExecuteCmd(createPullCmd(), "--overwrite-newer")
   136  	if err != nil {
   137  		panic(err)
   138  	}
   139  	require.NoError(t, err)
   140  	ac, err = ts.Store.ReadAccountClaim("A")
   141  	require.NoError(t, err)
   142  	require.Empty(t, ac.Tags)
   143  }
   144  
   145  func Test_SyncNewerFromNatsResolver(t *testing.T) {
   146  	ts := NewEmptyStore(t)
   147  	defer ts.Done(t)
   148  	_, _, err := ExecuteCmd(CreateAddOperatorCmd(), "--name", "OP", "--sys")
   149  	require.NoError(t, err)
   150  	ts.SwitchOperator(t, "OP") // switch the operator so ts is in a usable state to obtain operator key
   151  	serverconf := filepath.Join(ts.Dir, "server.conf")
   152  	_, _, err = ExecuteCmd(createServerConfigCmd(), "--nats-resolver", "--config-file", serverconf)
   153  	require.NoError(t, err)
   154  	_, _, err = ExecuteCmd(CreateAddAccountCmd(), "--name", "AC1")
   155  	require.NoError(t, err)
   156  	// modify the generated file so testing becomes easier by knowing where the jwt directory is
   157  	data, err := ioutil.ReadFile(serverconf)
   158  	require.NoError(t, err)
   159  	dir, err := ioutil.TempDir("", "Test_SyncNatsResolver-jwt-")
   160  	require.NoError(t, err)
   161  	defer os.Remove(dir)
   162  	data = bytes.ReplaceAll(data, []byte(`dir: './jwt'`), []byte(fmt.Sprintf(`dir: '%s'`, dir)))
   163  	err = ioutil.WriteFile(serverconf, data, 0660)
   164  	require.NoError(t, err)
   165  	// Create a new account, only known to the nats-server. This account can be pulled
   166  	opKey, err := ts.Store.GetRootPublicKey()
   167  	require.NoError(t, err)
   168  	opKp, err := ts.KeyStore.GetKeyPair(opKey)
   169  	require.NoError(t, err)
   170  	acKp, err := nkeys.CreateAccount()
   171  	require.NoError(t, err)
   172  	subj, err := acKp.PublicKey()
   173  	require.NoError(t, err)
   174  	claimOrig := jwt.NewAccountClaims(subj)
   175  	claimOrig.Name = "acc-name"
   176  	theJwtToPull, err := claimOrig.Encode(opKp)
   177  	require.NoError(t, err)
   178  	ioutil.WriteFile(dir+string(os.PathSeparator)+subj+".jwt", []byte(theJwtToPull), 0660)
   179  	ports := ts.RunServerWithConfig(t, serverconf)
   180  	require.NotNil(t, ports)
   181  	// only after server start as ports are not yet known in tests
   182  	_, _, err = ExecuteCmd(CreateEditOperatorCmd(), "--account-jwt-server-url", ports.Nats[0])
   183  	require.NoError(t, err)
   184  	_, _, err = ExecuteCmd(createPullCmd(), "--all")
   185  	require.NoError(t, err)
   186  	// again, this time with system account and user specified
   187  	_, _, err = ExecuteCmd(createPullCmd(), "--all", "--system-account", "SYS", "--system-user", "sys")
   188  	require.NoError(t, err)
   189  	// claim now exists in nsc store
   190  	claim2, err := ts.Store.ReadAccountClaim("acc-name")
   191  	require.NoError(t, err)
   192  	require.NotEmpty(t, claimOrig.ID)
   193  	require.Equal(t, claimOrig.ID, claim2.ID)
   194  }
   195  
   196  func Test_V2OperatorDoesntFail(t *testing.T) {
   197  	_, _, okp := CreateOperatorKey(t)
   198  	as, m := RunTestAccountServerWithOperatorKP(t, okp, TasOpts{Vers: 2, OperatorOnlyIfV2: true})
   199  	defer as.Close()
   200  
   201  	ts := NewTestStoreWithOperator(t, "T", okp)
   202  	defer ts.Done(t)
   203  	err := ts.Store.StoreRaw(m["operator"])
   204  	require.NoError(t, err)
   205  
   206  	// edit the jwt
   207  	_, _, err = ExecuteCmd(createPullCmd(), "-A")
   208  	require.NoError(t, err)
   209  
   210  	oc, err := ts.Store.ReadOperatorClaim()
   211  	require.NoError(t, err)
   212  	require.Equal(t, oc.Version, 2)
   213  }
   214  
   215  func Test_V1OperatorDoesntFail(t *testing.T) {
   216  	_, _, okp := CreateOperatorKey(t)
   217  	as, m := RunTestAccountServerWithOperatorKP(t, okp, TasOpts{Vers: 2})
   218  	defer as.Close()
   219  
   220  	ts := NewTestStoreWithOperator(t, "T", okp)
   221  	defer ts.Done(t)
   222  	err := ts.Store.StoreRaw(m["operator"])
   223  	require.NoError(t, err)
   224  
   225  	// edit the jwt
   226  	stdout, stderr, err := ExecuteCmd(createPullCmd(), "-A")
   227  	t.Log(stdout)
   228  	t.Log(stderr)
   229  	require.NoError(t, err)
   230  
   231  	oc, err := ts.Store.ReadOperatorClaim()
   232  	require.NoError(t, err)
   233  	require.Equal(t, oc.Version, 2)
   234  }