-
Notifications
You must be signed in to change notification settings - Fork 0
/
feed.xml
1597 lines (1326 loc) · 88 KB
/
feed.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
<title>Finecloud</title>
<link href="https://www.finecloud.ch/feed.xml" rel="self" />
<link href="https://www.finecloud.ch" />
<updated>2024-09-13T22:50:31+02:00</updated>
<author>
<name>Finecloud</name>
</author>
<id>https://www.finecloud.ch</id>
<entry>
<title>Automatically update the hidden dependencies in your Dockerfiles</title>
<author>
<name>Finecloud</name>
</author>
<link href="https://www.finecloud.ch/automatically-update-hidden-dependencies-in-your-dockerfiles.html"/>
<id>https://www.finecloud.ch/automatically-update-hidden-dependencies-in-your-dockerfiles.html</id>
<category term="software development"/>
<category term="renovate"/>
<category term="regex"/>
<category term="maven"/>
<category term="linux"/>
<category term="docker"/>
<category term="devops"/>
<category term="container"/>
<category term="bash"/>
<updated>2024-09-13T17:23:46+02:00</updated>
<summary>
<![CDATA[
You have probably already heard about Renovate - the fantastic tool that helps you to keep your dependencies up to date. But today, we want to look at an edge case: how to keep your dependencies in your dependencies up to date (also called hidden…
]]>
</summary>
<content type="html">
<![CDATA[
<p>
You have probably already heard about Renovate - the fantastic tool that helps you to keep your dependencies up to date.
</p>
<p>
But today, we want to look at an edge case: how to keep your dependencies in your dependencies up to date (also called hidden dependencies)?
</p>
<p>
Atlassian provides a Confluence image. If you want to run this with an Oracle database, you have to inject the Oracle JDBC driver yourself. But how can you ensure that you automatically always will have the most recent OJDBC driver in your Confluence image?
</p>
<pre class=" language-docker"><code>FROM atlassian/confluence:8.5.15-ubuntu-jdk17
# Download the ojdbc driver
RUN curl -fSL "https://repo1.maven.org/maven2/com/oracle/database/jdbc/ojdbc10/19.23.0.0/ojdbc10-19.23.0.0.jar" \
-o "${CONFLUENCE_INSTALL_DIR}/confluence/WEB-INF/lib/ojdbc10.jar"
</code></pre>
<p>
First of all, let's extract the semantic version tag from the URL into a separate ARG so that Renovate only needs to bump the version there:
</p>
<pre class=" language-docker"><code>FROM atlassian/confluence:8.5.15-ubuntu-jdk17
ARG OJDBC_VERSION=19.24.0.0
# Download the ojdbc driver
RUN curl -fSL "https://repo1.maven.org/maven2/com/oracle/database/jdbc/ojdbc10/${OJDBC_VERSION}/ojdbc10-${OJDBC_VERSION}.jar" \
-o "${CONFLUENCE_INSTALL_DIR}/confluence/WEB-INF/lib/ojdbc10.jar"
</code></pre>
<p>
Next, we will add a comment directly above the ARG OJDBC version, which we will later use to tell Renovate what dependency type and package this version tag is about. It's a maven package with the package name "com.oracle.database.jdbc:ojdbc10":
</p>
<pre class=" language-docker"><code>FROM atlassian/confluence:8.5.15-ubuntu-jdk17
# renovate: datasource=maven depName=com.oracle.database.jdbc:ojdbc10 packageName=com.oracle.database.jdbc:ojdbc10
ARG OJDBC_VERSION=19.24.0.0
# Download the ojdbc driver
RUN curl -fSL "https://repo1.maven.org/maven2/com/oracle/database/jdbc/ojdbc10/${OJDBC_VERSION}/ojdbc10-${OJDBC_VERSION}.jar" \
-o "${CONFLUENCE_INSTALL_DIR}/confluence/WEB-INF/lib/ojdbc10.jar"</code></pre>
<p>
You could write a custom regex manager in the Renovate config that updates this version tag. But what if you have multiple ARG or ENV version tags in multiple Dockerfiles within the same repo? You Probably don't want to write a regex config for each case.
</p>
<p>
Let's imagine you have something like this in your Dockerfile:
</p>
<pre class=" language-docker"><code># renovate: datasource=github-tags depName=node packageName=nodejs/node versioning=node
ENV NODE_VERSION=20.10.0
# renovate: datasource=github-releases depName=composer packageName=composer/composer
ENV COMPOSER_VERSION=1.9.3
# renovate: datasource=docker packageName=docker versioning=docker
ENV DOCKER_VERSION=19.03.1
# renovate: datasource=npm packageName=yarn
ENV YARN_VERSION=1.19.1</code></pre>
<p>
All you now need is the following regex configuration in your <em>renovate.json</em> config to detect and bump all of these version tags:
</p>
<pre class=" language-json"><code>{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended"
],
"separateMinorPatch": true,
"customManagers": [
{
"customType": "regex",
"description": "Update _VERSION variables in Dockerfiles",
"fileMatch": ["(^|/|\\.)Dockerfile$", "(^|/)Dockerfile\\.[^/]*$"],
"matchStrings": [
"# renovate: datasource=(?<datasource>[a-z-]+?)(?: depName=(?<depName>.+?))? packageName=(?<packageName>.+?)(?: versioning=(?<versioning>[a-z-]+?))?\\s(?:ENV|ARG) .+?_VERSION=(?<currentValue>.+?)\\s"
]
}
]
}</code></pre>
<p>
Now, you could even set up auto merge for these Renovate updates. Make sure you have some merge checks before you enable this. At least you should ensure that the Docker image can still be built before a new Renovate pull request gets auto-merged.
</p>
<p>
✨ Happy renovating! ✨
</p>
]]>
</content>
</entry>
<entry>
<title>GitHub classic vs. fine-grained Personal Access Tokens</title>
<author>
<name>Finecloud</name>
</author>
<link href="https://www.finecloud.ch/github-classic-vs-fine-grained-personal-access-tokens.html"/>
<id>https://www.finecloud.ch/github-classic-vs-fine-grained-personal-access-tokens.html</id>
<category term="security"/>
<category term="github"/>
<category term="devops"/>
<updated>2024-07-31T17:32:59+02:00</updated>
<summary>
<![CDATA[
What are PATs? Personal access tokens are an alternative to using passwords for authentication to GitHub when using the GitHub API or the command line. Personal access tokens are intended to access GitHub resources on your behalf. To access resources on behalf of an organization,…
]]>
</summary>
<content type="html">
<![CDATA[
<div class="post__toc">
<h3>Contents</h3>
<ul>
<li><a href="#what-are-pats">What are PATs?</a></li><li><a href="#what-are-classic-pats">What are classic PATs?</a></li><li><a href="#what-are-fine-grained-pats">What are fine-grained PATs?</a></li><li><a href="#what-happens-when-the-user-who-generated-them-becomes-inactive-and-loses-access-to-the-resource">What happens when the user who generated them becomes inactive and loses access to the resource?</a></li><li><a href="#what-are-the-risks-to-consider-with-pats">What are the risks to consider with PATs?</a></li><li><a href="#can-a-classic-pat-owned-by-a-regular-gh-user-be-used-to-access-and-manipulate-a-gh-internal-repo-from-externally-without-any-other-auth-requirement">Can a classic PAT (owned by a regular GH user) be used to access and manipulate a GH internal Repo from externally without any other auth requirement?</a></li><li><a href="#can-a-fine-grained-pat-owned-by-a-regular-gh-user-be-used-to-access-and-manipulate-a-gh-internal-repo-from-externally-without-any-other-auth-requirement">Can a fine-grained PAT (owned by a regular GH User) be used to access and manipulate a GH internal Repo from externally without any other auth requirement?</a></li><li><a href="#can-a-fine-grained-pat-owned-by-the-org-be-used-to-access-and-manipulate-a-gh-internal-repo-externally-without-any-other-auth-requirement">Can a fine-grained PAT (owned by the Org) be used to access and manipulate a GH internal Repo externally without any other auth requirement?</a></li><li><a href="#how-can-org-admins-restrict-classic-pats-access-to-the-org">How can Org. Admins restrict classic PATs access to the Org?</a></li><li><a href="#how-can-you-manage-classic-pats-of-the-users-as-an-org-adminlessbrgreater">How can you manage classic PATs of the Users as an Org Admin?<br></a></li><li><a href="#how-can-i-restrict-org-access-of-fine-grained-pats-as-an-org-admin">How can I restrict Org access of fine-grained PATs as an Org Admin?</a></li><li><a href="#how-can-i-manage-fine-grained-pats-of-the-users-as-an-org-admin">How can I manage fine-grained PATs of the Users as an Org Admin?</a></li><li><a href="#overview-of-classic-vs-fine-grained-pats">Overview of Classic vs. Fine-grained PATs</a></li>
</ul>
</div>
<h2 id="what-are-pats">
What are PATs?
</h2>
<p>
Personal access tokens are an alternative to using passwords for authentication to GitHub when using the <a href="https://docs.github.com/en/rest/overview/authenticating-to-the-rest-api" target="_blank">GitHub API</a> or the <a href="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#using-a-personal-access-token-on-the-command-line" target="_blank">command line</a>.<br><br>Personal access tokens are intended to access GitHub resources on your behalf. <strong>To access resources on behalf of an organization, or for long-lived integrations, you should use a GitHub App. For more information, see "<a href="https://docs.github.com/en/apps/creating-github-apps/setting-up-a-github-app/about-creating-github-apps" target="_blank">About creating GitHub Apps</a>"</strong><br><br><strong>GitHub recommends that you use fine-grained personal access tokens instead of personal access tokens (classic) whenever possible. (<a href="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#types-of-personal-access-tokens" target="_blank">source</a>)</strong>
</p>
<h2 id="what-are-classic-pats">
What are classic PATs?
</h2>
<p>
Personal access tokens (classic) are less secure. <strong>However, some features currently will only work with personal access tokens (classic):</strong>
</p>
<ul>
<li><span style="color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: 1em; font-weight: var(--font-weight-normal);">Only personal access tokens (classic) have write access for public repositories that are not owned by you or an organization that you are not a member of.</span><br></li><li>Outside collaborators can only use personal access tokens (classic) to access organization repositories that they are a collaborator on.</li><li>A few REST API endpoints are only available with a personal access tokens (classic). To check whether an endpoint also supports fine-grained personal access tokens, see the documentation for that endpoint, or see "<a href="https://docs.github.com/en/rest/overview/endpoints-available-for-fine-grained-personal-access-tokens" target="_blank">Endpoints available for fine-grained personal access tokens</a>".</li>
</ul>
<p>
If you choose to use a personal access token (classic), keep in mind that it will grant access to all repositories within the organizations that you have access to, as well as all personal repositories in your personal account.<br><br>As a security precaution, GitHub automatically removes personal access tokens that haven't been used in a year. To provide additional security, we highly recommend adding an expiration to your personal access tokens.
</p>
<h2 id="what-are-fine-grained-pats">
What are fine-grained PATs?
</h2>
<p>
Fine-grained personal access tokens have several security advantages over personal access tokens (classic):
</p>
<ul>
<li>Each token can only access resources owned by a single user or organization.</li><li>Each token can only access specific repositories.</li><li>Each token is granted specific permissions, which offer more control than the scopes granted to personal access tokens (classic).</li><li>Each token must have an expiration date.</li><li>Organization owners can require approval for any fine-grained personal access tokens that can access resources in the organization.</li>
</ul>
<h2 id="what-happens-when-the-user-who-generated-them-becomes-inactive-and-loses-access-to-the-resource">
What happens when the user who generated them becomes inactive and loses access to the resource?
</h2>
<p>
Both fine-grained personal access tokens and personal access tokens (classic) are tied to the user who generated them and will become inactive if the user loses access to the resource.
</p>
<h2 id="what-are-the-risks-to-consider-with-pats">
What are the risks to consider with PATs?
</h2>
<ul>
<li>PATs could be leaked if they get into the wrong hands and are used externally</li><li> Org. Admins don't see users classic PATs with Org. access</li>
</ul>
<h2 id="can-a-classic-pat-owned-by-a-regular-gh-user-be-used-to-access-and-manipulate-a-gh-internal-repo-from-externally-without-any-other-auth-requirement">
Can a classic PAT (owned by a regular GH user) be used to access and manipulate a GH internal Repo from externally without any other auth requirement?
</h2>
<p>
Yes. You need to create a classic PAT, select all permissions and then try to access an internal GitHub Test Repo from an external Computer without any VPN/internal access or SSO auth session. You will be able to pull all the Repo content and write everywhere where the owner of the PAT has access, e.g., create Issues, close PRs, etc.
</p>
<h2 id="can-a-fine-grained-pat-owned-by-a-regular-gh-user-be-used-to-access-and-manipulate-a-gh-internal-repo-from-externally-without-any-other-auth-requirement">
Can a fine-grained PAT (owned by a regular GH User) be used to access and manipulate a GH internal Repo from externally without any other auth requirement?
</h2>
<p>
Per default, user-owned fine-grained PATs have only read access to public github.com repos. To select access to an internal GH Repo, the Organization must own the PAT, which is only possible if the token request gets approved by an Org. Admin.
</p>
<h2 id="can-a-fine-grained-pat-owned-by-the-org-be-used-to-access-and-manipulate-a-gh-internal-repo-externally-without-any-other-auth-requirement">
Can a fine-grained PAT (owned by the Org) be used to access and manipulate a GH internal Repo externally without any other auth requirement?
</h2>
<p>
Once the requested PAT got approved by an Org Admin, yes, this is possible. But the token has a maximum lifetime of 1 year. If the user of the PAT changes something on the permissions, the review workflow is again triggered, and an Org Admin must approve the permission change before it is applied.
</p>
<h2 id="how-can-org-admins-restrict-classic-pats-access-to-the-org">
How can Org. Admins restrict classic PATs access to the Org?
</h2>
<p>
Organization owners/admins can prevent personal access tokens (classic) from accessing resources owned by the organization. Personal access tokens (classic) can still read public resources within the organization.
</p>
<figure class="post__image post__image--center">
<img loading="lazy" src="https://www.finecloud.ch/media/posts/104/gh-token.png" height="258" width="934" alt="" sizes="100vw" srcset="https://www.finecloud.ch/media/posts/104/responsive/gh-token-xs.png 300w ,https://www.finecloud.ch/media/posts/104/responsive/gh-token-sm.png 480w ,https://www.finecloud.ch/media/posts/104/responsive/gh-token-md.png 768w ,https://www.finecloud.ch/media/posts/104/responsive/gh-token-lg.png 1024w ,https://www.finecloud.ch/media/posts/104/responsive/gh-token-xl.png 1360w ,https://www.finecloud.ch/media/posts/104/responsive/gh-token-2xl.png 1600w">
</figure>
<p>
https://github.com/organizations/<your-gh-org-name>/settings/personal-access-tokens
</p>
<h2 id="how-can-you-manage-classic-pats-of-the-users-as-an-org-adminlessbrgreater">
How can you manage classic PATs of the Users as an Org Admin?<br>
</h2>
<p>
You can't, because you don't see them. Only the User who created the classic PAT can see and manage it.
</p>
<h2 id="how-can-i-restrict-org-access-of-fine-grained-pats-as-an-org-admin">
How can I restrict Org access of fine-grained PATs as an Org Admin?
</h2>
<figure class="post__image post__image--center">
<img loading="lazy" src="https://www.finecloud.ch/media/posts/104/gh-token-2.png" height="264" width="928" alt="" sizes="100vw" srcset="https://www.finecloud.ch/media/posts/104/responsive/gh-token-2-xs.png 300w ,https://www.finecloud.ch/media/posts/104/responsive/gh-token-2-sm.png 480w ,https://www.finecloud.ch/media/posts/104/responsive/gh-token-2-md.png 768w ,https://www.finecloud.ch/media/posts/104/responsive/gh-token-2-lg.png 1024w ,https://www.finecloud.ch/media/posts/104/responsive/gh-token-2-xl.png 1360w ,https://www.finecloud.ch/media/posts/104/responsive/gh-token-2-2xl.png 1600w">
</figure>
<p>
https://github.com/organizations/<your-gh-org-name><your-gh-org-name>/settings/personal-access-tokens</your-gh-org-name><br>
</p>
<h2 id="how-can-i-manage-fine-grained-pats-of-the-users-as-an-org-admin">
How can I manage fine-grained PATs of the Users as an Org Admin?
</h2>
<p>
You can't manage/see the fine-grained PATs the User Account owns. Once the Org owns the PAT, you can see and manage them.<br><br>If the owner is set to the User, the PAT is invisible/unable to manage, but this also means that token only has access to public repos:
</p>
<figure class="post__image post__image--center">
<img loading="lazy" src="https://www.finecloud.ch/media/posts/104/SCR-20240805-qyyf.png" height="429" width="996" alt="" sizes="100vw" srcset="https://www.finecloud.ch/media/posts/104/responsive/SCR-20240805-qyyf-xs.png 300w ,https://www.finecloud.ch/media/posts/104/responsive/SCR-20240805-qyyf-sm.png 480w ,https://www.finecloud.ch/media/posts/104/responsive/SCR-20240805-qyyf-md.png 768w ,https://www.finecloud.ch/media/posts/104/responsive/SCR-20240805-qyyf-lg.png 1024w ,https://www.finecloud.ch/media/posts/104/responsive/SCR-20240805-qyyf-xl.png 1360w ,https://www.finecloud.ch/media/posts/104/responsive/SCR-20240805-qyyf-2xl.png 1600w">
</figure>
<p>
If you select the Organization as the Resource owner of the PAT instead, a fine-grained personal access token request will be made, which needs to be approved by an Org. Admin before it can be used.
</p>
<p>
An overview of all Org. owned PATs can be found under this URL; if you are an Org. Admin: https://github.com/organizations/<your-gh-org-name>/settings/personal-access-tokens/active
</p>
<h2 id="overview-of-classic-vs-fine-grained-pats">
Overview of Classic vs. Fine-grained PATs
</h2>
<div><style type="text/css">
.tg {border-collapse:collapse;border-spacing:0;}
.tg td{border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px;
overflow:hidden;padding:10px 5px;word-break:normal;}
.tg th{border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px;
font-weight:normal;overflow:hidden;padding:10px 5px;word-break:normal;}
.tg .tg-wp8o{text-align:center;vertical-align:top}
.tg .tg-73oq{text-align:left;vertical-align:top}
</style>
<table class="tg"><thead>
<tr>
<th class="tg-73oq"></th>
<th class="tg-wp8o">Classic PAT</th>
<th class="tg-wp8o">Fine-grained PAT</th>
</tr></thead>
<tbody>
<tr>
<td class="tg-73oq">write access for public repositories that are not owned by you or an organization that you are not a member of</td>
<td class="tg-wp8o">✅</td>
<td class="tg-wp8o">❌</td>
</tr>
<tr>
<td class="tg-73oq">Outside collaborators can access organization repositories that they are a collaborator on.</td>
<td class="tg-wp8o">✅</td>
<td class="tg-wp8o">❌</td>
</tr>
<tr>
<td class="tg-73oq">Can be used with all REST API endpoints</td>
<td class="tg-wp8o">✅</td>
<td class="tg-wp8o">❌</td>
</tr>
<tr>
<td class="tg-73oq">Feature release status</td>
<td class="tg-wp8o">stable</td>
<td class="tg-wp8o">beta<br></td>
</tr>
<tr>
<td class="tg-73oq">Tokens must have an expiration date</td>
<td class="tg-wp8o">❌</td>
<td class="tg-wp8o">✅</td>
</tr>
<tr>
<td class="tg-73oq">Token can inherit all permissions of the User, incl. all repositories <br>within the organizations that the user has access to without any <br>approval/reivew</td>
<td class="tg-wp8o">✅</td>
<td class="tg-wp8o">❌</td>
</tr>
<tr>
<td class="tg-73oq">Token permissions can be defined set on repository level (fine-grained)</td>
<td class="tg-wp8o">❌</td>
<td class="tg-wp8o">✅</td>
</tr>
<tr>
<td class="tg-73oq">Organization owners can prevent token from accessing resources owned by the organization</td>
<td class="tg-wp8o">✅</td>
<td class="tg-wp8o">✅</td>
</tr>
<tr>
<td class="tg-73oq">Organization owners can require approval for each token that can access <br>the organization (e.g. internal Repo) from externally without any other <br>auth requirement</td>
<td class="tg-wp8o">❌</td>
<td class="tg-wp8o">✅</td>
</tr>
</tbody></table>
</div>
]]>
</content>
</entry>
<entry>
<title>Third-party GitHub Actions</title>
<author>
<name>Finecloud</name>
</author>
<link href="https://www.finecloud.ch/third-party-github-actions.html"/>
<id>https://www.finecloud.ch/third-party-github-actions.html</id>
<category term="security"/>
<category term="github"/>
<updated>2024-04-08T20:50:51+02:00</updated>
<summary>
<![CDATA[
Today I came across these steps to guide our decision-making process, before using a 3rd Part GitHub Action:
]]>
</summary>
<content type="html">
<![CDATA[
<p>
Today I came across these steps to guide our decision-making process, before using a 3rd Part GitHub Action:
</p>
<ol>
<li><span style="color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: 1em; font-weight: var(--font-weight-normal);">For simple tasks, avoid external GitHub Actions because the risk might outweigh the value. Maybe a simple curl could to it as well? 😉</span><br></li><li><span style="color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: 1em; font-weight: var(--font-weight-normal);">Use GitHub Actions from Verified Creators because they follow a strict security review process.</span><br></li><li><span style="color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: 1em; font-weight: var(--font-weight-normal);">Use the latest version of a GitHub Action because it might contain security fixes.</span><br></li><li><span style="color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: 1em; font-weight: var(--font-weight-normal);">Think about GitHub Actions like dependencies: they need to be maintained and updated. Dependabot or Renovate can help here.</span><br></li><li><span style="color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: 1em; font-weight: var(--font-weight-normal);">Think about disabling or limiting GitHub Actions for your organization(s) in Settings.</span><br></li><li><span style="color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: 1em; font-weight: var(--font-weight-normal);">Have a PR process with multiple reviewers to avoid adding a malicious GitHub Action.</span><br></li>
</ol>
<p>
</p>
]]>
</content>
</entry>
<entry>
<title>GitHub Codespace</title>
<author>
<name>Finecloud</name>
</author>
<link href="https://www.finecloud.ch/github-codespace.html"/>
<id>https://www.finecloud.ch/github-codespace.html</id>
<category term="software development"/>
<category term="github"/>
<category term="git"/>
<category term="codespace"/>
<updated>2024-04-05T21:02:42+02:00</updated>
<summary>
<![CDATA[
What is a Codespace? A codespace is a development environment that's hosted in the cloud. You can customize your project for GitHub Codespaces by committing configuration files to your repository (also known as configuration-as-code), which creates a repeatable codespace configuration for all users of your…
]]>
</summary>
<content type="html">
<![CDATA[
<h2 id="what-is-a-codespace">
What is a Codespace?
</h2>
<p>
A codespace is a development environment that's hosted in the cloud. You can customize your project for GitHub Codespaces by committing configuration files to your repository (also known as configuration-as-code), which creates a repeatable codespace configuration for all users of your project. Each codespace you create is hosted by GitHub in a Docker container that runs on a virtual machine. You can choose the type of machine you want to use depending on the resources you need.
</p>
<h2 id="how-can-i-create-a-codespace">
How can I create a Codespace?
</h2>
<p>
There are four ways to create a Codespace:
</p>
<ul>
<li>From a GitHub template or any template repository on GitHub.com to start a new project.</li><li> From a branch in your repository for new feature work.</li><li> From an open pull request to explore work-in-progress.</li><li> From a commit in a repository's history to investigate a bug at a specific point in time.</li>
</ul>
<p>
The easiest way to start a Codespace is by clicking the green Code button and then choosing open in a Codespace:
</p>
<figure class="post__image post__image--center">
<img loading="lazy" src="https://www.finecloud.ch/media/posts/102/SCR-20240405-stqz.png" height="892" width="942" alt="" sizes="100vw" srcset="https://www.finecloud.ch/media/posts/102/responsive/SCR-20240405-stqz-xs.png 300w ,https://www.finecloud.ch/media/posts/102/responsive/SCR-20240405-stqz-sm.png 480w ,https://www.finecloud.ch/media/posts/102/responsive/SCR-20240405-stqz-md.png 768w ,https://www.finecloud.ch/media/posts/102/responsive/SCR-20240405-stqz-lg.png 1024w ,https://www.finecloud.ch/media/posts/102/responsive/SCR-20240405-stqz-xl.png 1360w ,https://www.finecloud.ch/media/posts/102/responsive/SCR-20240405-stqz-2xl.png 1600w">
</figure>
<h4 id="what-happens-when-i-create-a-codespace">
What happens when I create a Codespace?
</h4>
<p>
When you create a GitHub Codespace, four processes occur:
</p>
<ol>
<li>VM and storage are assigned to your Codespace.</li><li> A container is created.</li><li> A connection to the Codespace is made.</li><li> A post-creation setup is made.</li>
</ol>
<h2 id="what-you-can-customize">
What you can customize
</h2>
<p>
There are many ways you can customize your Codespace. Let's review each one.
</p>
<ul>
<li>Settings Sync: You can synchronize your Visual Studio Code (VS Code) settings between the desktop application and the VS Code web client.</li><li>Dotfiles: You can use a dotfiles repository to specify scripts, shell preferences, and other configurations.<br></li><li> Rename a Codespace: When you create a Codespace, it's assigned an autogenerated display name. If you have multiple Codespaces, the display name helps you to differentiate between Codespaces. You can change the display name for your Codespace.<br></li><li> Change your shell: You can change your shell in a Codespace to keep the setup you're used to. When you're working in a Codespace, you can open a new terminal window with a shell of your choice, change your default shell for new terminal windows, or install a new shell. You can also use dotfiles to configure your shell.<br></li><li> Change the machine type: You can change the type of machine that's running your Codespace, so that you're using resources appropriate for the work you're doing.<br></li><li> Set the default editor: You can set your default editor for Codespaces in your personal settings page. Set your editor preference so that when you create a Codespace or open an existing Codespace, it opens to your default editor.<br>- Visual Studio Code (desktop application)<br>- Visual Studio Code (web client application)<br>- JetBrains Gateway - for opening Codespaces in a JetBrains IDE<br>- JupyterLab - the web interface for Project Jupyter<br></li><li> Set the default region: You can set your default region in the GitHub Codespaces profile settings page to personalize where your data is held.<br></li><li> Set the timeout: A Codespace will stop running after a period of inactivity. By default this period is 30 minutes, but you can specify a longer or shorter default timeout period in your personal settings on GitHub. The updated setting applies to any new Codespaces you create, or to existing Codespaces the next time you start them.</li><li>Configure automatic deletion: Inactive Codespaces are automatically deleted. You can choose how long your stopped Codespaces are retained, up to a maximum of 30 days.<br></li>
</ul>
<h2 id="difference-betweenandnbspcodespaces-and-githubdev-editor">
Difference between Codespaces and GitHub.dev editor
</h2>
<h4 id="when-should-i-use-github-codespaces-and-when-should-i-use-githubdev">
when should I use GitHub Codespaces and when should I use GitHub.dev?
</h4>
<p>
GitHub.dev is a good fit if you only want to navigate some files and sources code repositories from GitHub, and maybe make and commit small code changes.
</p>
<p>
On the other hand, if you want to run a bunch of tests with your code, or build a heavy application you better use GitHub Codespaces. It has compute associated with it so you can build your code, run your code, and have terminal access. GitHub.dev doesn't have compute in it. With GitHub Codespaces, you get the power of a personal Virtual Machine (VM) with terminal access, the same way you could use your local environment, just in the cloud.
</p>
<div><table>
<tr>
<th></th>
<th>GitHub.dev</th>
<th>GitHub Codespaces</th>
</tr>
<tr>
<td>Cost</td>
<td>Free</td>
<td>Free monthly quota of usage for personal accounts</td>
</tr>
<tr>
<td>Availability</td>
<td>Available to everyone on GitHub.com</td>
<td>Available to everyone on GitHub.com</td>
</tr>
<tr>
<td>Startup</td>
<td>GitHub.dev opens instantly with a key-press and you can start using it right away without having to wait for configuration or installation</td>
<td>When you create or resume a Codespace, the Codespace is assigned a VM, and the container is configured based on the contents of a devcontainer.json file. This setup takes a few minutes to create the development environment.</td>
</tr>
<tr>
<td>Compute</td>
<td>There's no associated compute, so you can't build and run your code or use the integrated terminal.</td>
<td>With GitHub Codespaces, you get the power of a dedicated VM to run and debug your application.</td>
</tr>
<tr>
<td>Terminal access</td>
<td>None</td>
<td>GitHub Codespaces provides a common set of tools by default, meaning that you can use the Terminal exactly as you would in your local environment.</td>
</tr>
<tr>
<td>Extensions</td>
<td>Only a subset of extensions that can run on the web appear in the extensions view and can be installed</td>
<td>With GitHub Codespaces, you can use most extensions from the Visual Studio Code Marketplace.</td>
</tr>
</table>
</div>
<h2 id="using-codespace-images">
Using Codespace images
</h2>
<p>
One of the biggest benefits of codespaces is that Github ships images with the most recent and common tools you need to develop. Have a look at this Repository: <a href="https://github.com/devcontainers/images/tree/main/src/universal" target="_blank" rel="nofollow noopener">https://github.com/devcontainers/images/tree/main/src/universal</a>
</p>
]]>
</content>
</entry>
<entry>
<title>Awk and Sed</title>
<author>
<name>Finecloud</name>
</author>
<link href="https://www.finecloud.ch/awk-and-sed.html"/>
<id>https://www.finecloud.ch/awk-and-sed.html</id>
<category term="shell"/>
<category term="sed"/>
<category term="linux"/>
<category term="bash"/>
<category term="awk"/>
<updated>2024-04-05T20:57:46+02:00</updated>
<summary>
<![CDATA[
awk and sed are text manipulation programs. You can use them for example to replace strings: echo image.jpg | sed 's/\.jpg/.png/' image.png or change order of strings: echo "hello world" | awk '{print $2, $1}' world hello awk and sed are harder to learn than…
]]>
</summary>
<content type="html">
<![CDATA[
<p>
awk and sed are text manipulation programs. You can use them for example to replace strings:
</p>
<pre class=" language-bash"><code>echo image.jpg | sed 's/\.jpg/.png/'
image.png
</code></pre>
<p>
or change order of strings:<br>
</p>
<pre class=" language-bash"><code>echo "hello world" | awk '{print $2, $1}'
world hello
</code></pre>
<p>
awk and sed are harder to learn than some other basic linux cli tools because they contain their own small programming language.<br>
</p>
<h2 id="awk-basics">
awk basics
</h2>
<p>
awk transforms lines of text (stdin) into any other text, using a set of instructions (called the awk program):
</p>
<pre class=" language-bash"><code>awk program input-files
</code></pre>
<p>
a awk program can also contain one or more `actions`, for example calculating values or printing text. These `actions` run only when an input matches a `pattern`:<br>`pattern {action}`
</p>
<p>
typical patterns include:
</p>
<ul>
<li>`BEGIN` runs once before the awk processes any input</li><li>`END` run once after awk has processed all the input</li><li>A Regex surrounded by forward slashes, example: `/^[A-Z]/`</li><li>other awk specific expressions, example: `FNR>5` tells awk to skip the first five lines of input</li>
</ul>
<p>
<br>A `pattern` with no `action` runs the default action `{print}` .<br>awk can also perform calculations such as these:
</p>
<pre class=" language-bash"><code>seq 1 100 | awk '{s+=$1} END {print s}'
5050</code></pre>
<p>
(sum numbers 1 to 100)
</p>
<h2 id="sed-basics">
sed basics
</h2>
<p>
sed like awk can be used to transform text from stdin to any other text using instructions called `sed scripts`:
</p>
<pre class=" language-bash"><code>sed script input-files</code></pre>
<p>
the most common use case for sed is text replacement, like in this example:<br>
</p>
<pre class=" language-bash"><code>echo "Windows eats Linux for breakfast" | sed s/Windows/Linux/g | sed s/Linux/Windows/2
</code></pre>
<p>
</p>
]]>
</content>
</entry>
<entry>
<title>How to do a code review</title>
<author>
<name>Finecloud</name>
</author>
<link href="https://www.finecloud.ch/how-to-do-a-code-review.html"/>
<id>https://www.finecloud.ch/how-to-do-a-code-review.html</id>
<category term="software development"/>
<category term="devops"/>
<updated>2024-03-18T08:44:04+01:00</updated>
<summary>
<![CDATA[
This Blog post is my personal summary of Googles code review process Make sure to review every line of code you’ve been asked to review, look at the context, make sure you’re improving code health, and compliment developers on good things that they do. Look at…
]]>
</summary>
<content type="html">
<![CDATA[
<p>
This Blog post is my personal summary of <a href="https://google.github.io/eng-practices/review/" target="_blank" rel="nofollow noopener">Googles code review process</a>
</p>
<p>
</p>
<div class="post__toc">
<h3>Table of contents</h3>
<ul>
<li><a href="#summary-of-what-you-should-look-at">Summary of what you should look at</a></li><li><a href="#the-standard-of-code-review">The Standard of Code Review</a></li><li><a href="#navigate-a-pull-request-pr-in-review">Navigate a Pull-Request (PR) in review</a><ul><li><a href="#1-take-a-broad-view-of-the-change">1. Take a broad view of the change</a></li><li><a href="#2-examine-the-main-parts-of-the-pr">2. Examine the main parts of the PR</a></li><li><a href="#3andnbsplook-through-the-rest-of-the-pr-in-an-appropriate-sequence">3. Look through the rest of the PR in an appropriate sequence</a></li></ul></li><li><a href="#speed-of-code-reviews">Speed of Code Reviews</a><ul><li><a href="#approve-with-comments">Approve with Comments</a></li></ul></li><li><a href="#how-to-write-comments">How to write comments</a></li>
</ul>
</div>
<h2 id="summary-of-what-you-should-look-at">
Summary of what you should look at
</h2>
<ul>
<li><strong>Design</strong>: Is the code well-designed and appropriate for your system?<br></li><li> <strong>Functionality</strong>: Does the code behave as the author likely intended? Is the way the code behaves good for its users?</li><li><strong>Complexity</strong>: Could the code be made simpler? Would another developer be able to easily understand and use this code when they come across it in the future?</li><li><strong>Tests</strong>: Does the code have correct and well-designed automated tests?<br></li><li> <strong>Naming</strong>: Did the developer choose clear names for variables, classes, methods, etc.?</li><li><strong>Comments</strong>: Are the comments clear and useful?</li><li><strong>Style</strong>: Does the code follow our style guides?</li><li><strong>Documentation</strong>: Did the developer also update relevant documentation?<br></li>
</ul>
<p>
Make sure to review <strong>every line</strong> of code you’ve been asked to review, look at the <strong>context</strong>, make sure you’re <strong>improving code health</strong>, and compliment developers on <strong>g</strong><strong>ood things</strong> that they do.
</p>
<h2 id="the-standard-of-code-review">
The Standard of Code Review
</h2>
<ul>
<li>You need to balance the tradeoff between making progress, by letting a change go into your code base and not decreasing overall code health and quality. </li><li><span style="color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: 1em; font-weight: var(--font-weight-normal);">does the Pull-Request improve the maintainability, readability, and understandability?</span><br></li><li><strong>In general you should try to approve a Pull-Request (PR) once it is in a state where it definitely improves the overall code health, even if the PR isn’t perfect.</strong></li><li>Reviewers should not require the author to polish every tiny piece of a CL before granting approval. Rather, the reviewer should balance out the need to make forward progress compared to the importance of the changes they are suggesting. </li><li>Instead of seeking perfection, what a reviewer should seek is continuous improvement.</li><li>If you add a comment on a PR to mention something could be better, but it’s optional and not very important, prefix it with something like “Nit: “ to let the author know that it’s just a point of polish that they could choose to ignore.</li>
</ul>
<h2 id="navigate-a-pull-request-pr-in-review">
Navigate a Pull-Request (PR) in review
</h2>
<h3 id="1-take-a-broad-view-of-the-change">
1. Take a broad view of the change
</h3>
<p>
Look at the PR description and what the PR does in general. Does this change even make sense? If this change shouldn’t have happened in the first place, please respond immediately with an explanation of why the change should not be happening. When you reject a change like this, it’s also a good idea to suggest to the developer what they should have done instead.
</p>
<h3 id="2-examine-the-main-parts-of-the-pr">
2. Examine the main parts of the PR
</h3>
<p>
Find the file or files that are the “main” part of this PR. Often, there is one file that has the largest number of logical changes, and it’s the major piece of the PR. Look at these major parts first. This helps give context to all of the smaller parts of the PR, and generally accelerates doing the code review.
</p>
<h3 id="3andnbsplook-through-the-rest-of-the-pr-in-an-appropriate-sequence">
3. Look through the rest of the PR in an appropriate sequence
</h3>
<p>
Once you’ve confirmed there are no major design problems with the CL as a whole, try to figure out a logical sequence to look through the files while also making sure you don’t miss reviewing any file.
</p>
<h2 id="speed-of-code-reviews">
Speed of Code Reviews
</h2>
<p>
Why is it so important that you send comments out immediately, especially if you see major design problems within a PR?
</p>
<ul>
<li>Developers often open a PR and then immediately start new work based on that PR (e.g. feature branch) while they wait for review. If there are major design problems in the PR you’re reviewing, they’re also going to have to re-work their later PR. You want to catch them before they’ve done too much extra work on top of the problematic design.</li><li>Major design changes take longer to do than small changes. Developers nearly all have deadlines; in order to make those deadlines and still have quality code in the codebase, the developer needs to start on any major re-work of the PR as soon as possible.<br></li>
</ul>
<p>
When code reviews are slow, several things happen:
</p>
<ul>
<li>The velocity of the team as a whole is decreased.</li><li>Developers start to protest the code review process. Most complaints about the code review process are actually resolved by making the process faster.</li><li>Code health can be impacted.<br></li>
</ul>
<p>
How fast should a code review be?
</p>
<ul>
<li>If you are not in the middle of a focused task, <strong>you should do a code review shortly after it comes in</strong>.</li><li><strong>One business day is the maximum time it should take to respond</strong> to a code review request (i.e., first thing the next morning).</li>
</ul>
<p>
<strong>If you are in the middle of a focused task, such as writing code, don’t interrupt yourself to do a code review</strong>. Research has shown that it can take a long time for a developer to get back into a smooth flow of development after being interrupted. So interrupting yourself while coding is actually more expensive to the team than making another developer wait a bit for a code review.
</p>
<h3 id="approve-with-comments">
Approve with Comments
</h3>
<p>
In order to speed up code reviews, there are certain situations in which a reviewer should give the Approval even though they are also leaving unresolved comments on the PR. This is done when either:
</p>
<ul>
<li>The reviewer is confident that the developer will appropriately address all the reviewer’s remaining comments.</li><li> The remaining changes are minor and don’t have to be done by the developer.</li>
</ul>
<h2 id="how-to-write-comments">
How to write comments
</h2>
<ul>
<li>Be kind.</li><li>Explain your reasoning (why?).</li><li>Balance giving explicit directions with just pointing out problems and letting the developer decide -> In general it is the developer’s responsibility to fix a PR, not the reviewer’s.</li><li>Encourage developers to simplify code or add code comments instead of just explaining the complexity to you.<br></li>
</ul>
]]>
</content>
</entry>
<entry>
<title>Building a GraphQL service</title>
<author>
<name>Finecloud</name>
</author>
<link href="https://www.finecloud.ch/building-a-graphql-service.html"/>
<id>https://www.finecloud.ch/building-a-graphql-service.html</id>
<category term="spring-framework"/>
<category term="spring"/>
<category term="software development"/>
<category term="java"/>
<category term="graphql"/>
<category term="api"/>
<updated>2024-01-22T21:19:17+01:00</updated>
<summary>
<![CDATA[
Let's build a GraphQL Spring Application that will accept GraphQL requests at http://localhost:8080/graphql. First let's navigate to https://start.spring.io. This service pulls in all the dependencies you need for an application and does most of the setup for you. GraphQL is a query language to retrieve…
]]>
</summary>
<content type="html">
<![CDATA[
<div class="post__toc">
<h3>Table of contents</h3>
<ul>
<li><a href="#preparation">Preparation</a></li><li><a href="#a-very-short-introduction-to-graphql">A very short introduction to GraphQL</a></li><li><a href="#our-example-api-getting-book-details">Our example API: getting book details</a></li><li><a href="#schema">Schema</a></li><li><a href="#source-of-the-data">Source of the data</a></li><li><a href="#create-the-book-and-author-data-sources">Create the Book and Author data sources</a></li><li><a href="#adding-code-to-fetch-data">Adding code to fetch data</a></li><li><a href="#running-our-first-query">Running our first query</a><ul><li><a href="#enable-the-graphiql-playground">Enable the GraphiQL Playground</a></li><li><a href="#boot-the-application">Boot the application</a></li><li><a href="#run-the-query">Run the query</a></li></ul></li><li><a href="#testing">Testing</a></li>
</ul>
</div>
<p>
Let's build a GraphQL Spring Application that will accept GraphQL requests at http://localhost:8080/graphql.
</p>
<h2 id="preparation">
Preparation
</h2>
<p>
First let's navigate to https://start.spring.io. This service pulls in all the dependencies you need for an application and does most of the setup for you.<br>
</p>
<ul>
<li>Choose Maven and chose Java.Click </li><li>Dependencies and select Spring for GraphQL and Spring Web.</li><li><span style="color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: 1em; font-weight: var(--font-weight-normal);">Click Generate.</span><br></li><li><span style="color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: 1em; font-weight: var(--font-weight-normal);">Download the resulting ZIP file, which is an archive of a GraphQL application that is configured with your choices.</span><br></li><li>Unzip and open the Folder with your favorite IDE (IntelliJ recommended)</li>
</ul>
<h2 id="a-very-short-introduction-to-graphql">
A very short introduction to GraphQL
</h2>
<p>
GraphQL is a query language to retrieve data from a server. It is an alternative to REST, SOAP, or gRPC. In the next Part we will query the details for a specific book from an online store backend.<br><br>This is an example request you can send to a GraphQL server to retrieve book details:
</p>
<pre class=" language-graphql"><code>query bookDetails {
bookById(id: "book-1") {
id
name
pageCount
author {
firstName
lastName
}
}
}</code></pre>
<p>
This GraphQL request says:
</p>
<ul>
<li>perform a query for a book with id "book-1"</li><li><span style="color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: 1em; font-weight: var(--font-weight-normal);">for the book, return id, name, pageCount and author</span><br></li><li><span style="color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: 1em; font-weight: var(--font-weight-normal);">for the author, return firstName and lastName</span><br></li>
</ul>
<p>
The response is in JSON. For example:<br>
</p>
<pre class=" language-json"><code>{
"bookById": {
"id":"book-1",
"name":"Effective Java",
"pageCount":416,
"author": {
"firstName":"Joshua",
"lastName":"Bloch"
}
}
}</code></pre>
<p>
An important feature of GraphQL is that it defines a schema language, and that it is statically typed. The server knows exactly what types of objects requests can query and what fields those objects contain. Furthermore, clients can introspect the server to ask for schema details.
</p>
<p class="msg msg--info">
The word schema in this Post refers to a "GraphQL Schema", which is not related to other schemas like "JSON Schema" or "Database Schema".
</p>
<p>
The schema for the above query is:
</p>
<pre class=" language-graphql"><code>type Query {
bookById(id: ID): Book
}
type Book {
id: ID
name: String
pageCount: Int
author: Author
}
type Author {
id: ID
firstName: String
lastName: String
}</code></pre>
<p>
This Post will focus on how to implement a GraphQL server with this schema in Java.<br><br>We’ve barely scratched the surface of what’s possible with GraphQL. Further information can be found on the official GraphQL page.
</p>
<h2 id="our-example-api-getting-book-details">
Our example API: getting book details
</h2>
<p>
These are the main steps to create a server with Spring for GraphQL:
</p>
<ol>
<li>Define a GraphQL schema</li><li>Implement the logic to fetch the actual data for a query<br></li>
</ol>
<p>
Our example app will be a simple API to get details for a specific book. It is not intended to be a comprehensive API.
</p>
<h2 id="schema">
Schema
</h2>
<p>
In your Spring for GraphQL application prepared earlier, add a new file <em>schema.graphqls</em> to the <em>src/main/resources/graphql</em> folder with the following content:
</p>
<pre class=" language-graphql"><code>type Query {
bookById(id: ID): Book
}
type Book {
id: ID
name: String
pageCount: Int
author: Author
}
type Author {
id: ID
firstName: String
lastName: String
}</code></pre>
<p>
Every GraphQL schema has a top-level <em>Query</em> type, and the fields under it are the query operations exposed by the application. Here the schema defines one query called <em>bookById</em> that returns the details of a specific book.<br><br>It also defines the types <em>Book</em> with fields<em> id, name, pageCount</em> and <em>author</em>, and the type <em>Author</em> with fields <em>firstName</em> and <em>lastName</em>.<br>
</p>
<p class="msg msg--info">
The Domain Specific Language used above to describe a schema is called the Schema Definition Language or SDL. For more details, see the GraphQL documentation.
</p>
<h2 id="source-of-the-data">
Source of the data
</h2>
<p>
A key strength of GraphQL is that data can be sourced from anywhere. Data can come from a database, an external service, or a static in-memory list.<br><br>To simplify the demo here, book and author data will come from static lists inside their respective classes.
</p>
<h2 id="create-the-book-and-author-data-sources">
Create the Book and Author data sources
</h2>
<p>
Let’s now create the <em>Book</em> and <em>Author</em> classes in the main application package, right next to <em>GraphQlServerApplication</em>. Use the following as their content:
</p>
<pre class=" language-java"><code>package com.example.graphqlserver;
import java.util.Arrays;
import java.util.List;
public record Book (String id, String name, int pageCount, String authorId) {
private static List<Book> books = Arrays.asList(
new Book("book-1", "Effective Java", 416, "author-1"),
new Book("book-2", "Hitchhiker's Guide to the Galaxy", 208, "author-2"),
new Book("book-3", "Down Under", 436, "author-3")
);
public static Book getById(String id) {
return books.stream()
.filter(book -> book.id().equals(id))
.findFirst()
.orElse(null);
}
}</code></pre>
<pre class=" language-java"><code>package com.example.graphqlserver;
import java.util.Arrays;
import java.util.List;
public record Author (String id, String firstName, String lastName) {
private static List<Author> authors = Arrays.asList(
new Author("author-1", "Joshua", "Bloch"),
new Author("author-2", "Douglas", "Adams"),
new Author("author-3", "Bill", "Bryson")
);
public static Author getById(String id) {
return authors.stream()
.filter(author -> author.id().equals(id))
.findFirst()
.orElse(null);
}
}</code></pre>
<h2 id="adding-code-to-fetch-data">
Adding code to fetch data
</h2>
<p>
Spring for GraphQL provides an annotation-based programming model. With controller annotated methods, we can declare how to fetch the data for specific GraphQL fields.<br><br>Add the following to <em>BookController.java</em> in the main application package, next to Book and Author:
</p>
<pre class=" language-java"><code>package com.example.graphqlserver;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.graphql.data.method.annotation.SchemaMapping;
import org.springframework.stereotype.Controller;
@Controller