• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

square / keywhiz / 3998983595

pending completion
3998983595

push

github

GitHub
Merge pull request #1189 from square/chloeb/datasec-677

Adding CLI option to the "describe secrets" action to include deleted secrets

42 of 42 new or added lines in 4 files covered. (100.0%)

5237 of 6968 relevant lines covered (75.16%)

0.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.53
/cli/src/main/java/keywhiz/cli/Printing.java
1
/*
2
 * Copyright (C) 2015 Square, Inc.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package keywhiz.cli;
17

18
import com.fasterxml.jackson.core.JsonProcessingException;
19
import com.fasterxml.jackson.databind.ObjectMapper;
20
import com.google.common.base.Strings;
21
import com.google.common.base.Throwables;
22
import java.io.IOException;
23
import java.text.DateFormat;
24
import java.util.Comparator;
25
import java.util.Date;
26
import java.util.List;
27
import java.util.Optional;
28
import javax.annotation.Nullable;
29
import javax.inject.Inject;
30
import keywhiz.api.ClientDetailResponse;
31
import keywhiz.api.GroupDetailResponse;
32
import keywhiz.api.SecretDetailResponse;
33
import keywhiz.api.model.Client;
34
import keywhiz.api.model.Group;
35
import keywhiz.api.model.SanitizedSecret;
36
import keywhiz.client.KeywhizClient;
37

38
public class Printing {
39
  private final KeywhizClient keywhizClient;
40

41
  private static final String INDENT = "\t";
42
  private static final String DOUBLE_INDENT = Strings.repeat(INDENT, 2);
1✔
43

44
  @Inject
45
  public Printing(final KeywhizClient keywhizClient) {
×
46
    this.keywhizClient = keywhizClient;
×
47
  }
×
48

49
  public void printClientWithDetails(Client client) {
50
    System.out.println(client.getName());
×
51
    ClientDetailResponse clientDetails;
52
    try {
53
      clientDetails = keywhizClient.clientDetailsForId(client.getId());
×
54
    } catch (IOException e) {
×
55
      throw Throwables.propagate(e);
×
56
    }
×
57

58
    System.out.println(INDENT + "Groups:");
×
59
    clientDetails.groups.stream()
×
60
        .sorted(Comparator.comparing(Group::getName))
×
61
        .forEach(g -> System.out.println(DOUBLE_INDENT + g.getName()));
×
62

63
    System.out.println(INDENT + "Secrets:");
×
64
    clientDetails.secrets.stream()
×
65
        .sorted(Comparator.comparing(SanitizedSecret::name))
×
66
        .forEach(s -> System.out.println(DOUBLE_INDENT + SanitizedSecret.displayName(s)));
×
67

68
    if (clientDetails.lastSeen == null) {
×
69
      System.out.println(INDENT + "Last Seen: never");
×
70
    } else {
71
      Date d = new Date(clientDetails.lastSeen.toEpochSecond() * 1000);
×
72
      System.out.printf(INDENT + "Last Seen: %s%n", DateFormat.getDateTimeInstance().format(d));
×
73
    }
74

75
    if (!clientDetails.description.isEmpty()) {
×
76
      System.out.println(INDENT + "Description:");
×
77
      System.out.println(DOUBLE_INDENT + clientDetails.description);
×
78
    }
79

80
    if (clientDetails.spiffeId != null && !clientDetails.spiffeId.isEmpty()) {
×
81
      System.out.println(INDENT + "Spiffe ID:");
×
82
      System.out.println(DOUBLE_INDENT + clientDetails.spiffeId);
×
83
    }
84

85
    if (!clientDetails.createdBy.isEmpty()) {
×
86
      System.out.println(INDENT + "Created by:");
×
87
      System.out.println(DOUBLE_INDENT + clientDetails.createdBy);
×
88
    }
89

90
    System.out.println(INDENT + "Created at:");
×
91
    Date d = new Date(clientDetails.creationDate.toEpochSecond() * 1000);
×
92
    System.out.println(DOUBLE_INDENT + DateFormat.getDateTimeInstance().format(d));
×
93

94
    if (!clientDetails.updatedBy.isEmpty()) {
×
95
      System.out.println(INDENT + "Updated by:");
×
96
      System.out.println(DOUBLE_INDENT + clientDetails.updatedBy);
×
97
    }
98

99
    System.out.println(INDENT + "Updated at:");
×
100
    d = new Date(clientDetails.updateDate.toEpochSecond() * 1000);
×
101
    System.out.println(DOUBLE_INDENT + DateFormat.getDateTimeInstance().format(d));
×
102
  }
×
103

104
  public void printGroupWithDetails(Group group) {
105
    System.out.println(group.getName());
×
106
    GroupDetailResponse groupDetails;
107
    try {
108
      groupDetails = keywhizClient.groupDetailsForId(group.getId());
×
109
    } catch (IOException e) {
×
110
      throw Throwables.propagate(e);
×
111
    }
×
112

113
    System.out.println(INDENT + "Clients:");
×
114
    groupDetails.getClients().stream()
×
115
        .sorted(Comparator.comparing(Client::getName))
×
116
        .forEach(c -> System.out.println(DOUBLE_INDENT + c.getName()));
×
117

118
    System.out.println(INDENT + "Secrets:");
×
119
    groupDetails.getSecrets().stream()
×
120
        .sorted(Comparator.comparing(SanitizedSecret::name))
×
121
        .forEach(s -> System.out.println(DOUBLE_INDENT + SanitizedSecret.displayName(s)));
×
122

123
    System.out.println(INDENT + "Metadata:");
×
124
    if (!groupDetails.getMetadata().isEmpty()) {
×
125
      String metadata;
126
      try {
127
        metadata = new ObjectMapper().writeValueAsString(groupDetails.getMetadata());
×
128
      } catch (JsonProcessingException e) {
×
129
        throw Throwables.propagate(e);
×
130
      }
×
131
      System.out.println(DOUBLE_INDENT + metadata);
×
132
    }
133

134
    if (!groupDetails.getDescription().isEmpty()) {
×
135
      System.out.println(INDENT + "Description:");
×
136
      System.out.println(DOUBLE_INDENT + groupDetails.getDescription());
×
137
    }
138

139
    if (!groupDetails.getCreatedBy().isEmpty()) {
×
140
      System.out.println(INDENT + "Created by:");
×
141
      System.out.println(DOUBLE_INDENT + groupDetails.getCreatedBy());
×
142
    }
143

144
    System.out.println(INDENT + "Created at:");
×
145
    Date d = new Date(groupDetails.getCreationDate().toEpochSecond() * 1000);
×
146
    System.out.println(DOUBLE_INDENT + DateFormat.getDateTimeInstance().format(d));
×
147

148
    if (!groupDetails.getUpdatedBy().isEmpty()) {
×
149
      System.out.println(INDENT + "Updated by:");
×
150
      System.out.println(DOUBLE_INDENT + groupDetails.getUpdatedBy());
×
151
    }
152

153
    System.out.println(INDENT + "Updated at:");
×
154
    d = new Date(groupDetails.getUpdateDate().toEpochSecond() * 1000);
×
155
    System.out.println(DOUBLE_INDENT + DateFormat.getDateTimeInstance().format(d));
×
156
  }
×
157

158
  public void printDeletedSecretsWithDetails(@Nullable List<SanitizedSecret> deletedSecrets) {
159
    int deletedCount = deletedSecrets == null ? 0 : deletedSecrets.size();
×
160
    System.out.println(String.format("Deleted Secrets: found %d", deletedCount));
×
161
    if (deletedSecrets != null) {
×
162
      deletedSecrets.forEach(this::printSanitizedSecretWithDetails);
×
163
    }
164
  }
×
165

166
  public void printNonDeletedSecretWithDetails(@Nullable SanitizedSecret secret) {
167
    if (secret == null) {
×
168
      System.out.println("No non-deleted secret found.");
×
169
    } else {
170
      printSanitizedSecretWithDetails(secret);
×
171
    }
172
  }
×
173

174
  public void printSanitizedSecretWithDetails(SanitizedSecret secret) {
175
    System.out.println(SanitizedSecret.displayName(secret));
×
176
    SecretDetailResponse secretDetails;
177
    try {
178
      secretDetails = keywhizClient.secretDetailsForId(secret.id());
×
179
    } catch (IOException e) {
×
180
      throw Throwables.propagate(e);
×
181
    }
×
182

183
    System.out.println(INDENT + "Internal ID:");
×
184
    System.out.println(DOUBLE_INDENT + secret.id());
×
185

186
    System.out.println(INDENT + "Owner:");
×
187
    if (secret.owner() != null) {
×
188
      System.out.println(DOUBLE_INDENT + secret.owner());
×
189
    }
190

191
    System.out.println(INDENT + "Groups:");
×
192
    secretDetails.groups.stream()
×
193
        .sorted(Comparator.comparing(Group::getName))
×
194
        .forEach(g -> System.out.println(DOUBLE_INDENT + g.getName()));
×
195

196
    System.out.println(INDENT + "Clients:");
×
197
    secretDetails.clients.stream()
×
198
        .sorted(Comparator.comparing(Client::getName))
×
199
        .forEach(c -> System.out.println(DOUBLE_INDENT + c.getName()));
×
200

201
    System.out.println(INDENT + "Content HMAC:");
×
202
    if (secret.checksum().isEmpty()) {
×
203
      System.out.println(DOUBLE_INDENT + "WARNING: Content HMAC not calculated!");
×
204
    } else {
205
      System.out.println(DOUBLE_INDENT + secret.checksum());
×
206
    }
207

208
    System.out.println(INDENT + "Metadata:");
×
209
    if (!secret.metadata().isEmpty()) {
×
210
      String metadata;
211
      try {
212
        metadata = new ObjectMapper().writeValueAsString(secret.metadata());
×
213
      } catch (JsonProcessingException e) {
×
214
        throw Throwables.propagate(e);
×
215
      }
×
216
      System.out.println(DOUBLE_INDENT + metadata);
×
217
    }
218

219
    if (secret.expiry() > 0) {
×
220
      System.out.println(INDENT + "Expiry:");
×
221
      Date d = new Date(secret.expiry() * 1000);
×
222
      System.out.println(DOUBLE_INDENT + DateFormat.getDateTimeInstance().format(d));
×
223
    }
224

225
    if (!secret.description().isEmpty()) {
×
226
      System.out.println(INDENT + "Description:");
×
227
      System.out.println(DOUBLE_INDENT + secret.description());
×
228
    }
229

230
    if (!secret.createdBy().isEmpty()) {
×
231
      System.out.println(INDENT + "Created by:");
×
232
      System.out.println(DOUBLE_INDENT + secret.createdBy());
×
233
    }
234

235
    System.out.println(INDENT + "Created at:");
×
236
    Date d = new Date(secret.createdAt().toEpochSecond() * 1000);
×
237
    System.out.println(DOUBLE_INDENT + DateFormat.getDateTimeInstance().format(d));
×
238

239
    if (!secret.updatedBy().isEmpty()) {
×
240
      System.out.println(INDENT + "Updated by:");
×
241
      System.out.println(DOUBLE_INDENT + secret.updatedBy());
×
242
    }
243

244
    System.out.println(INDENT + "Updated at:");
×
245
    d = new Date(secret.updatedAt().toEpochSecond() * 1000);
×
246
    System.out.println(DOUBLE_INDENT + DateFormat.getDateTimeInstance().format(d));
×
247

248
    if (!secret.contentCreatedBy().isEmpty()) {
×
249
      System.out.println(INDENT + "Content created by:");
×
250
      System.out.println(DOUBLE_INDENT + secret.contentCreatedBy());
×
251
    }
252

253
    if (secret.contentCreatedAt().isPresent()) {
×
254
      System.out.println(INDENT + "Content created at:");
×
255
      d = new Date(secret.contentCreatedAt().get().toEpochSecond() * 1000);
×
256
      System.out.println(DOUBLE_INDENT + DateFormat.getDateTimeInstance().format(d));
×
257
    }
258
  }
×
259

260
  public void printAllClients(List<Client> clients) {
261
    clients.stream()
×
262
        .sorted(Comparator.comparing(Client::getName))
×
263
        .forEach(c -> System.out.println(c.getName()));
×
264
  }
×
265

266
  public void printAllGroups(List<Group> groups) {
267
    groups.stream()
×
268
        .sorted(Comparator.comparing(Group::getName))
×
269
        .forEach(g -> System.out.println(g.getName()));
×
270
  }
×
271

272
  public void printAllSanitizedSecrets(List<SanitizedSecret> secrets) {
273
    secrets.stream()
×
274
        .sorted(Comparator.comparing(SanitizedSecret::name))
×
275
        .forEach(s -> System.out.println(SanitizedSecret.displayName(s)));
×
276
  }
×
277

278
  public void printSecretVersions(List<SanitizedSecret> versions, Optional<Long> currentVersion) {
279
    if (versions.isEmpty()) {
×
280
      return;
×
281
    }
282

283
    System.out.println(versions.get(0).name() + '\n');
×
284

285
    if (currentVersion.isEmpty()) {
×
286
      System.out.println("Current secret version unknown!");
×
287
    }
288

289
    for (SanitizedSecret secret : versions) {
×
290
      if (secret.version().isPresent()) {
×
291
        if (currentVersion.isPresent() && secret.version().get().equals(currentVersion.get())) {
×
292
          System.out.println(
×
293
              String.format("*** Current secret version id: %d ***", secret.version().get()));
×
294
        } else {
295
          System.out.println(String.format("Version id for rollback: %d", secret.version().get()));
×
296
        }
297
      } else {
298
        System.out.println("Version id for rollback: Unknown!");
×
299
      }
300

301
      if (secret.contentCreatedAt().isPresent()) {
×
302
        if (secret.contentCreatedBy().isEmpty()) {
×
303
          System.out.println(INDENT + String.format("Created on %s (creator unknown)",
×
304
              DateFormat.getDateTimeInstance()
×
305
                  .format(new Date(secret.contentCreatedAt().get().toEpochSecond() * 1000))));
×
306
        } else {
307
          System.out.println(
×
308
              INDENT + String.format("Created by %s on %s", secret.contentCreatedBy(),
×
309
                  DateFormat.getDateTimeInstance()
×
310
                      .format(new Date(secret.contentCreatedAt().get().toEpochSecond() * 1000))));
×
311
        }
312
      } else {
313
        if (secret.contentCreatedBy().isEmpty()) {
×
314
          System.out.println(INDENT + "Creator and creation date unknown");
×
315
        } else {
316
          System.out.println(
×
317
              INDENT + String.format("Created by %s (date unknown)", secret.contentCreatedBy()));
×
318
        }
319
      }
320

321
      if (secret.expiry() == 0) {
×
322
        System.out.println(INDENT + "Does not expire");
×
323
      } else {
324
        System.out.println(INDENT + String.format("Expires on %s", DateFormat.getDateTimeInstance()
×
325
            .format(new Date(secret.expiry() * 1000))));
×
326
      }
327

328
      if (!secret.metadata().isEmpty()) {
×
329
        System.out.println(INDENT + String.format("Metadata: %s", secret.metadata()));
×
330
      }
331

332
      if (!secret.checksum().isEmpty()) {
×
333
        System.out.println(INDENT + String.format("Content HMAC: %s", secret.checksum()));
×
334
      }
335
      System.out.print("\n"); // Add space between the versions
×
336
    }
×
337
  }
×
338
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc